shithub: riscv

Download patch

ref: eb4ade60be10d0a039eb8e76001427947f2fbadb
parent: b9ff604c31a0b9e34c2c529a5e27454edbbf9fab
author: cinap_lenrek <[email protected]>
date: Sat Feb 11 03:33:22 EST 2012

FLAC audio support

--- a/rc/bin/play
+++ b/rc/bin/play
@@ -51,6 +51,8 @@
 			audio/oggdec
 		case *mp3* *mpeg*
 			audio/mp3dec
+		case *flac*
+			audio/flacdec
 		case *pls*
 			awk 'BEGIN {FS="="} /^File/{print $2}' | play1 plain
 		case *
--- /dev/null
+++ b/sys/src/cmd/audio/flacdec/flacdec.c
@@ -1,0 +1,177 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "FLAC/stream_decoder.h"
+
+int rate = 44100;
+
+typedef unsigned long ulong;
+typedef unsigned char uchar;
+typedef long long vlong;
+
+typedef struct Chan Chan;
+struct Chan
+{
+	ulong		phase;
+	FLAC__int32	last;
+	FLAC__int32	rand;
+};
+
+enum
+{
+	OutBits = 16,
+	Max = 32767,
+	Min = -32768,
+};
+
+#define PRNG(x) (((x)*0x19660dL + 0x3c6ef35fL) & 0xffffffffL)
+
+static uchar*
+resample(Chan *c, FLAC__int32 *src, uchar *dst, int mono, ulong delta, ulong count, ulong bps)
+{
+	FLAC__int32 last, val, out, rand;
+	ulong phase, pos, scale, lowmask, lowmask2;
+	vlong v;
+
+	scale = 0;
+	if(bps > OutBits){
+		scale = bps - OutBits;
+		lowmask = (1<<scale)-1;
+		lowmask2 = lowmask/2;
+	}
+
+	rand = c->rand;
+	last = c->last;
+	phase = c->phase;
+	pos = phase >> 16;
+	while(pos < count){
+		val = src[pos];
+		if(pos)
+			last = src[pos-1];
+
+		/* interpolate */
+		v = val;
+		v -= last;
+		v *= (phase & 0xFFFF);
+		out = last + (v >> 16);
+
+		/* scale / dithering */
+		if(scale){
+			out += (rand & lowmask) - lowmask2;
+			rand = PRNG(rand);
+			out >>= scale;
+		}
+
+		/* cliping */
+		if(out > Max)
+			out = Max;
+		else if(out < Min)
+			out = Min;
+
+		*dst++ = out;
+		*dst++ = out >> 8;
+		if(mono){
+			*dst++ = out;
+			*dst++ = out >> 8;
+		} else
+			dst += 2;
+		phase += delta;
+		pos = phase >> 16;
+	}
+	c->rand = rand;
+	c->last = val;
+	if(delta < 0x10000)
+		c->phase = phase & 0xFFFF;
+	else
+		c->phase = phase - (count << 16);
+
+	return dst;
+}
+
+static FLAC__StreamDecoderReadStatus
+decinput(FLAC__StreamDecoder *dec, FLAC__byte buffer[], unsigned *bytes, void *client_data)
+{
+	int n = *bytes;
+
+	n = fread(buffer,1,n,stdin);
+	if(n <= 0){
+		*bytes = 0;
+		return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+	} else {
+		*bytes = n;
+		return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+	}
+}
+
+static FLAC__StreamDecoderWriteStatus
+decoutput(FLAC__StreamDecoder *dec, FLAC__Frame *frame, FLAC__int32 *buffer[], void *client_data)
+{
+	static uchar *buf;
+	static int nbuf;
+	static Chan c1, c0;
+	ulong length, n, delta, bps;
+	uchar *p;
+
+	bps = frame->header.bits_per_sample;
+	length = frame->header.blocksize;
+	delta = (frame->header.sample_rate << 16) / rate;
+	n = 4 * (frame->header.sample_rate + length * rate) / frame->header.sample_rate;
+	if(n > nbuf){
+		nbuf = n;
+		buf = realloc(buf, nbuf);
+	}
+	if(frame->header.channels == 2)
+		resample(&c1, buffer[1], buf+2, 0, delta, length, bps);
+	p = resample(&c0, buffer[0], buf, frame->header.channels == 1, delta, length, bps);
+	fwrite(buf, p-buf, 1, stdout);
+	return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+
+static void
+decerror(FLAC__StreamDecoder *dec, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+}
+
+static void
+decmeta(FLAC__StreamDecoder *dec, FLAC__StreamMetadata *metadata, void *client_data)
+{
+}
+
+int main(int argc, char *argv[])
+{
+	FLAC__bool ok = true;
+	FLAC__StreamDecoder *dec = 0;
+	char *dbg;
+
+	dbg = "FLAC__stream_decoder_new";
+	if((dec = FLAC__stream_decoder_new()) == NULL)
+		goto Err;
+
+	dbg = "FLAC__stream_decoder_set_read_callback";
+	if(!FLAC__stream_decoder_set_read_callback(dec, decinput))
+		goto Err;
+
+	dbg = "FLAC__stream_decoder_set_write_callback";
+	if(!FLAC__stream_decoder_set_write_callback(dec, decoutput))
+		goto Err;
+
+	dbg = "FLAC__stream_decoder_set_error_callback";
+	if(!FLAC__stream_decoder_set_error_callback(dec, decerror))
+		goto Err;
+
+	dbg = "FLAC__stream_decoder_set_metadata_callback";
+	if(!FLAC__stream_decoder_set_metadata_callback(dec, decmeta))
+		goto Err;
+
+	dbg = "FLAC__stream_decoder_set_metadata_ignore_all";
+	if(!FLAC__stream_decoder_set_metadata_ignore_all(dec))
+		goto Err;
+
+	FLAC__stream_decoder_init(dec);
+	FLAC__stream_decoder_process_until_end_of_stream(dec);
+	FLAC__stream_decoder_finish(dec);
+	return 0;
+
+Err:
+	fprintf(stderr,"%s\n", dbg);
+	return 1;
+}
--- /dev/null
+++ b/sys/src/cmd/audio/flacdec/mkfile
@@ -1,0 +1,21 @@
+</$objtype/mkfile
+<../config
+
+TARGET=flacdec
+
+CC=pcc
+CFLAGS=-I. -I../libFLAC -I../libFLAC/FLAC -D_POSIX_SOURCE -D_BSD_EXTENSION -DPlan9 -c
+
+%.$O: %.c
+	$CC $CFLAGS -c $stem.c
+
+$O.%: %.$O ../libFLAC/libFLAC.a$O
+	$CC -o $target $prereq
+
+all:V: $O.$TARGET
+
+clean:V:
+	rm -f *.[$OS] [$OS].$TARGET
+
+install:V: $O.$TARGET
+	cp $O.$TARGET $BIN/$TARGET
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/FLAC/all.h
@@ -1,0 +1,158 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__ALL_H
+#define FLAC__ALL_H
+
+#include "export.h"
+
+#include "assert.h"
+#include "callback.h"
+#include "file_decoder.h"
+#include "file_encoder.h"
+#include "format.h"
+#include "metadata.h"
+#include "ordinals.h"
+#include "seekable_stream_decoder.h"
+#include "seekable_stream_encoder.h"
+#include "stream_decoder.h"
+#include "stream_encoder.h"
+
+/** \mainpage
+ *
+ * \section intro Introduction
+ *
+ * This is the documentation for the FLAC C and C++ APIs.  It is
+ * highly interconnected; this introduction should give you a top
+ * level idea of the structure and how to find the information you
+ * need.  As a prerequisite you should have at least a basic
+ * knowledge of the FLAC format, documented
+ * <A HREF="../format.html">here</A>.
+ *
+ * \section c_api FLAC C API
+ *
+ * The FLAC C API is the interface to libFLAC, a set of structures
+ * describing the components of FLAC streams, and functions for
+ * encoding and decoding streams, as well as manipulating FLAC
+ * metadata in files.  The public include files will be installed
+ * in your include area as <include>/FLAC/...
+ *
+ * By writing a little code and linking against libFLAC, it is
+ * relatively easy to add FLAC support to another program.  The
+ * library is licensed under <A HREF="../license.html">Xiph's BSD license</A>.
+ * Complete source code of libFLAC as well as the command-line
+ * encoder and plugins is available and is a useful source of
+ * examples.
+ *
+ * Aside from encoders and decoders, libFLAC provides a powerful
+ * metadata interface for manipulating metadata in FLAC files.  It
+ * allows the user to add, delete, and modify FLAC metadata blocks
+ * and it can automatically take advantage of PADDING blocks to avoid
+ * rewriting the entire FLAC file when changing the size of the
+ * metadata.
+ *
+ * libFLAC usually only requires the standard C library and C math
+ * library. In particular, threading is not used so there is no
+ * dependency on a thread library. However, libFLAC does not use
+ * global variables and should be thread-safe.
+ *
+ * There is also a new libOggFLAC library which wraps around libFLAC
+ * to provide routines for encoding to and decoding from FLAC streams
+ * inside an Ogg container.  The interfaces are very similar or identical
+ * to their counterparts in libFLAC.  libOggFLAC is also licensed under
+ * <A HREF="../license.html">Xiph's BSD license</A>.
+ *
+ * \section cpp_api FLAC C++ API
+ *
+ * The FLAC C++ API is a set of classes that encapsulate the
+ * structures and functions in libFLAC.  They provide slightly more
+ * functionality with respect to metadata but are otherwise
+ * equivalent.  For the most part, they share the same usage as
+ * their counterparts in libFLAC, and the FLAC C API documentation
+ * can be used as a supplement.  The public include files
+ * for the C++ API will be installed in your include area as
+ * <include>/FLAC++/...
+ *
+ * There is also a new libOggFLAC++ library, which provides classes
+ * for encoding to and decoding from FLAC streams in an Ogg container.
+ * The classes are very similar to their counterparts in libFLAC++.
+ *
+ * Both libFLAC++ libOggFLAC++ are also licensed under
+ * <A HREF="../license.html">Xiph's BSD license</A>.
+ *
+ * \section getting_started Getting Started
+ *
+ * A good starting point for learning the API is to browse through
+ * the <A HREF="modules.html">modules</A>.  Modules are logical
+ * groupings of related functions or classes, which correspond roughly
+ * to header files or sections of header files.  Each module includes a
+ * detailed description of the general usage of its functions or
+ * classes.
+ *
+ * From there you can go on to look at the documentation of
+ * individual functions.  You can see different views of the individual
+ * functions through the links in top bar across this page.
+ *
+ * \section embedded_developers Embedded Developers
+ *
+ * libFLAC has grown larger over time as more functionality has been
+ * included, but much of it may be unnecessary for a particular embedded
+ * implementation.  Unused parts may be pruned by some simple editing of
+ * src/libFLAC/Makefile.am.  In general, the decoders, encoders, and
+ * metadata interface are all independent from each other.
+ *
+ * It is easiest to just describe the dependencies:
+ *
+ * - All modules depend on the \link flac_format Format \endlink module.
+ * - The decoders and encoders are independent of each other.
+ * - The metadata interface requires the file decoder.
+ * - The decoder and encoder layers depend on the layers below them, but
+ *   not above them; e.g. the seekable stream decoder depends on the stream
+ *   decoder but not the file decoder
+ *
+ * For example, if your application only requires the stream decoder, no
+ * encoders, and no metadata interface, you can remove the seekable stream
+ * decoder, file decoder, all encoders, and the metadata interface, which
+ * will greatly reduce the size of the library.
+ */
+
+/** \defgroup flac FLAC C API
+ *
+ * The FLAC C API is the interface to libFLAC, a set of structures
+ * describing the components of FLAC streams, and functions for
+ * encoding and decoding streams, as well as manipulating FLAC
+ * metadata in files.
+ *
+ * You should start with the format components as all other modules
+ * are dependent on it.
+ */
+
+#endif
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/FLAC/assert.h
@@ -1,0 +1,45 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001,2002,2003,2004  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__ASSERT_H
+#define FLAC__ASSERT_H
+
+/* we need this since some compilers (like MSVC) leave assert()s on release code (and we don't want to use their ASSERT) */
+#ifdef DEBUG
+#include <assert.h>
+#define FLAC__ASSERT(x) assert(x)
+#define FLAC__ASSERT_DECLARATION(x) x
+#else
+#define FLAC__ASSERT(x)
+#define FLAC__ASSERT_DECLARATION(x)
+#endif
+
+#endif
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/FLAC/callback.h
@@ -1,0 +1,181 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2004  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__CALLBACK_H
+#define FLAC__CALLBACK_H
+
+#include "ordinals.h"
+#include <stdlib.h> /* for size_t */
+
+/** \file include/FLAC/callback.h
+ *
+ *  \brief
+ *  This module defines the structures for describing I/O callbacks
+ *  to the other FLAC interfaces.
+ *
+ *  See the detailed documentation for callbacks in the
+ *  \link flac_callbacks callbacks \endlink module.
+ */
+
+/** \defgroup flac_callbacks FLAC/callback.h: I/O callback structures
+ *  \ingroup flac
+ *
+ *  \brief
+ *  This module defines the structures for describing I/O callbacks
+ *  to the other FLAC interfaces.
+ *
+ *  The purpose of the I/O callback functions is to create a common way
+ *  for the metadata interfaces to handle I/O.
+ *
+ *  Originally the metadata interfaces required filenames as the way of
+ *  specifying FLAC files to operate on.  This is problematic in some
+ *  environments so there is an additional option to specify a set of
+ *  callbacks for doing I/O on the FLAC file, instead of the filename.
+ *
+ *  In addition to the callbacks, a FLAC__IOHandle type is defined as an
+ *  opaque structure for a data source.
+ *
+ *  The callback function prototypes are similar (but not identical) to the
+ *  stdio functions fread, fwrite, fseek, ftell, feof, and fclose.  If you use
+ *  stdio streams to implement the callbacks, you can pass fread, fwrite, and
+ *  fclose anywhere a FLAC__IOCallback_Read, FLAC__IOCallback_Write, or
+ *  FLAC__IOCallback_Close is required, and a FILE* anywhere a FLAC__IOHandle
+ *  is required.  \warning You generally can NOT directly use fseek or ftell
+ *  for FLAC__IOCallback_Seek or FLAC__IOCallback_Tell since on most systems
+ *  these use 32-bit offsets and FLAC requires 64-bit offsets to deal with
+ *  large files.  You will have to find an equivalent function (e.g. ftello),
+ *  or write a wrapper.  The same is true for feof() since this is usually
+ *  implemented as a macro, not as a function whose address can be taken.
+ *
+ * \{
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void* FLAC__IOHandle;
+
+/** Signature for the read callback.
+ *  The signature and semantics match POSIX fread() implementations
+ *  and can generally be used interchangeably.
+ *
+ * \param  ptr      The address of the read buffer.
+ * \param  size     The size of the records to be read.
+ * \param  nmemb    The number of records to be read.
+ * \param  handle   The handle to the data source.
+ * \retval size_t
+ *    The number of records read.
+ */
+typedef size_t (*FLAC__IOCallback_Read) (void *ptr, size_t size, size_t nmemb, FLAC__IOHandle handle);
+
+/** Signature for the write callback.
+ *  The signature and semantics match POSIX fwrite() implementations
+ *  and can generally be used interchangeably.
+ *
+ * \param  ptr      The address of the write buffer.
+ * \param  size     The size of the records to be written.
+ * \param  nmemb    The number of records to be written.
+ * \param  handle   The handle to the data source.
+ * \retval size_t
+ *    The number of records written.
+ */
+typedef size_t (*FLAC__IOCallback_Write) (const void *ptr, size_t size, size_t nmemb, FLAC__IOHandle handle);
+
+/** Signature for the seek callback.
+ *  The signature and semantics mostly match POSIX fseek() WITH ONE IMPORTANT
+ *  EXCEPTION: the offset is a 64-bit type whereas fseek() is generally 'long'
+ *  and 32-bits wide.
+ *
+ * \param  handle   The handle to the data source.
+ * \param  offset   The new position, relative to \a whence
+ * \param  whence   \c SEEK_SET, \c SEEK_CUR, or \c SEEK_END
+ * \retval int
+ *    \c 0 on success, \c -1 on error.
+ */
+typedef int (*FLAC__IOCallback_Seek) (FLAC__IOHandle handle, FLAC__int64 offset, int whence);
+
+/** Signature for the tell callback.
+ *  The signature and semantics mostly match POSIX ftell() WITH ONE IMPORTANT
+ *  EXCEPTION: the offset is a 64-bit type whereas ftell() is generally 'long'
+ *  and 32-bits wide.
+ *
+ * \param  handle   The handle to the data source.
+ * \retval FLAC__int64
+ *    The current position on success, \c -1 on error.
+ */
+typedef FLAC__int64 (*FLAC__IOCallback_Tell) (FLAC__IOHandle handle);
+
+/** Signature for the EOF callback.
+ *  The signature and semantics mostly match POSIX feof() but WATCHOUT:
+ *  on many systems, feof() is a macro, so in this case a wrapper function
+ *  must be provided instead.
+ *
+ * \param  handle   The handle to the data source.
+ * \retval int
+ *    \c 0 if not at end of file, nonzero if at end of file.
+ */
+typedef int (*FLAC__IOCallback_Eof) (FLAC__IOHandle handle);
+
+/** Signature for the close callback.
+ *  The signature and semantics match POSIX fclose() implementations
+ *  and can generally be used interchangeably.
+ *
+ * \param  handle   The handle to the data source.
+ * \retval int
+ *    \c 0 on success, \c EOF on error.
+ */
+typedef int (*FLAC__IOCallback_Close) (FLAC__IOHandle handle);
+
+/** A structure for holding a set of callbacks.
+ *  Each FLAC interface that requires a FLAC__IOCallbacks structure will
+ *  describe which of the callbacks are required.  The ones that are not
+ *  required may be set to NULL.
+ *
+ *  If the seek requirement for an interface is optional, you can signify that
+ *  a data sorce is not seekable by setting the \a seek field to \c NULL.
+ */
+typedef struct {
+	FLAC__IOCallback_Read read;
+	FLAC__IOCallback_Write write;
+	FLAC__IOCallback_Seek seek;
+	FLAC__IOCallback_Tell tell;
+	FLAC__IOCallback_Eof eof;
+	FLAC__IOCallback_Close close;
+} FLAC__IOCallbacks;
+
+/* \} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/FLAC/export.h
@@ -1,0 +1,47 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__EXPORT_H
+#define FLAC__EXPORT_H
+
+#if defined(FLAC__NO_DLL) || !defined(_MSC_VER)
+#define FLAC_API
+
+#else
+
+#ifdef FLAC_API_EXPORTS
+#define	FLAC_API	_declspec(dllexport)
+#else
+#define FLAC_API	_declspec(dllimport)
+
+#endif
+#endif
+#endif
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/FLAC/file_decoder.h
@@ -1,0 +1,660 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__FILE_DECODER_H
+#define FLAC__FILE_DECODER_H
+
+#include "export.h"
+#include "seekable_stream_decoder.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** \file include/FLAC/file_decoder.h
+ *
+ *  \brief
+ *  This module contains the functions which implement the file
+ *  decoder.
+ *
+ *  See the detailed documentation in the
+ *  \link flac_file_decoder file decoder \endlink module.
+ */
+
+/** \defgroup flac_file_decoder FLAC/file_decoder.h: file decoder interface
+ *  \ingroup flac_decoder
+ *
+ *  \brief
+ *  This module contains the functions which implement the file
+ *  decoder.
+ *
+ * The basic usage of this decoder is as follows:
+ * - The program creates an instance of a decoder using
+ *   FLAC__file_decoder_new().
+ * - The program overrides the default settings and sets callbacks for
+ *   writing, error reporting, and metadata reporting using
+ *   FLAC__file_decoder_set_*() functions.
+ * - The program initializes the instance to validate the settings and
+ *   prepare for decoding using FLAC__file_decoder_init().
+ * - The program calls the FLAC__file_decoder_process_*() functions
+ *   to decode data, which subsequently calls the callbacks.
+ * - The program finishes the decoding with FLAC__file_decoder_finish(),
+ *   which flushes the input and output and resets the decoder to the
+ *   uninitialized state.
+ * - The instance may be used again or deleted with
+ *   FLAC__file_decoder_delete().
+ *
+ * The file decoder is a trivial wrapper around the
+ * \link flac_seekable_stream_decoder seekable stream decoder \endlink
+ * meant to simplfy the process of decoding from a standard file.  The
+ * file decoder supplies all but the Write/Metadata/Error callbacks.
+ * The user needs only to provide the path to the file and the file
+ * decoder handles the rest.
+ *
+ * Like the seekable stream decoder, seeking is exposed through the
+ * FLAC__file_decoder_seek_absolute() method.  At any point after the file
+ * decoder has been initialized, the user can call this function to seek to
+ * an exact sample within the file.  Subsequently, the first time the write
+ * callback is called it will be passed a (possibly partial) block starting
+ * at that sample.
+ *
+ * The file decoder also inherits MD5 signature checking from the seekable
+ * stream decoder.  If this is turned on before initialization,
+ * FLAC__file_decoder_finish() will report when the decoded MD5 signature
+ * does not match the one stored in the STREAMINFO block.  MD5 checking is
+ * automatically turned off if there is no signature in the STREAMINFO
+ * block or when a seek is attempted.
+ *
+ * Make sure to read the detailed descriptions of the
+ * \link flac_seekable_stream_decoder seekable stream decoder module \endlink
+ * and \link flac_stream_decoder stream decoder module \endlink
+ * since the file decoder inherits much of its behavior from them.
+ *
+ * \note
+ * The "set" functions may only be called when the decoder is in the
+ * state FLAC__FILE_DECODER_UNINITIALIZED, i.e. after
+ * FLAC__file_decoder_new() or FLAC__file_decoder_finish(), but
+ * before FLAC__file_decoder_init().  If this is the case they will
+ * return \c true, otherwise \c false.
+ *
+ * \note
+ * FLAC__file_decoder_finish() resets all settings to the constructor
+ * defaults, including the callbacks.
+ *
+ * \{
+ */
+
+
+/** State values for a FLAC__FileDecoder
+ *
+ *  The decoder's state can be obtained by calling FLAC__file_decoder_get_state().
+ */
+typedef enum {
+
+	FLAC__FILE_DECODER_OK = 0,
+	/**< The decoder is in the normal OK state. */
+
+	FLAC__FILE_DECODER_END_OF_FILE,
+	/**< The decoder has reached the end of the file. */
+
+	FLAC__FILE_DECODER_ERROR_OPENING_FILE,
+	/**< An error occurred opening the input file. */
+
+	FLAC__FILE_DECODER_MEMORY_ALLOCATION_ERROR,
+	/**< An error occurred allocating memory. */
+
+	FLAC__FILE_DECODER_SEEK_ERROR,
+	/**< An error occurred while seeking. */
+
+	FLAC__FILE_DECODER_SEEKABLE_STREAM_DECODER_ERROR,
+	/**< An error occurred in the underlying seekable stream decoder. */
+
+	FLAC__FILE_DECODER_ALREADY_INITIALIZED,
+	/**< FLAC__file_decoder_init() was called when the decoder was already
+	 * initialized, usually because FLAC__file_decoder_finish() was not
+	 * called.
+	 */
+
+	FLAC__FILE_DECODER_INVALID_CALLBACK,
+	/**< FLAC__file_decoder_init() was called without all callbacks
+	 * being set.
+	 */
+
+	FLAC__FILE_DECODER_UNINITIALIZED
+	/**< The decoder is in the uninitialized state. */
+
+} FLAC__FileDecoderState;
+
+/** Maps a FLAC__FileDecoderState to a C string.
+ *
+ *  Using a FLAC__FileDecoderState as the index to this array
+ *  will give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__FileDecoderStateString[];
+
+
+/***********************************************************************
+ *
+ * class FLAC__FileDecoder : public FLAC__StreamDecoder
+ *
+ ***********************************************************************/
+
+struct FLAC__FileDecoderProtected;
+struct FLAC__FileDecoderPrivate;
+/** The opaque structure definition for the file decoder type.  See the
+ *  \link flac_file_decoder file decoder module \endlink for a detailed
+ *  description.
+ */
+typedef struct {
+	struct FLAC__FileDecoderProtected *protected_; /* avoid the C++ keyword 'protected' */
+	struct FLAC__FileDecoderPrivate *private_; /* avoid the C++ keyword 'private' */
+} FLAC__FileDecoder;
+
+/** Signature for the write callback.
+ *  See FLAC__file_decoder_set_write_callback()
+ *  and FLAC__SeekableStreamDecoderWriteCallback for more info.
+ *
+ * \param  decoder  The decoder instance calling the callback.
+ * \param  frame    The description of the decoded frame.
+ * \param  buffer   An array of pointers to decoded channels of data.
+ * \param  client_data  The callee's client data set through
+ *                      FLAC__file_decoder_set_client_data().
+ * \retval FLAC__StreamDecoderWriteStatus
+ *    The callee's return status.
+ */
+typedef FLAC__StreamDecoderWriteStatus (*FLAC__FileDecoderWriteCallback)(const FLAC__FileDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data);
+
+/** Signature for the metadata callback.
+ *  See FLAC__file_decoder_set_metadata_callback()
+ *  and FLAC__SeekableStreamDecoderMetadataCallback for more info.
+ *
+ * \param  decoder  The decoder instance calling the callback.
+ * \param  metadata The decoded metadata block.
+ * \param  client_data  The callee's client data set through
+ *                      FLAC__file_decoder_set_client_data().
+ */
+typedef void (*FLAC__FileDecoderMetadataCallback)(const FLAC__FileDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data);
+
+/** Signature for the error callback.
+ *  See FLAC__file_decoder_set_error_callback()
+ *  and FLAC__SeekableStreamDecoderErrorCallback for more info.
+ *
+ * \param  decoder  The decoder instance calling the callback.
+ * \param  status   The error encountered by the decoder.
+ * \param  client_data  The callee's client data set through
+ *                      FLAC__file_decoder_set_client_data().
+ */
+typedef void (*FLAC__FileDecoderErrorCallback)(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
+
+
+/***********************************************************************
+ *
+ * Class constructor/destructor
+ *
+ ***********************************************************************/
+
+/** Create a new file decoder instance.  The instance is created with
+ *  default settings; see the individual FLAC__file_decoder_set_*()
+ *  functions for each setting's default.
+ *
+ * \retval FLAC__FileDecoder*
+ *    \c NULL if there was an error allocating memory, else the new instance.
+ */
+FLAC_API FLAC__FileDecoder *FLAC__file_decoder_new();
+
+/** Free a decoder instance.  Deletes the object pointed to by \a decoder.
+ *
+ * \param decoder  A pointer to an existing decoder.
+ * \assert
+ *    \code decoder != NULL \endcode
+ */
+FLAC_API void FLAC__file_decoder_delete(FLAC__FileDecoder *decoder);
+
+
+/***********************************************************************
+ *
+ * Public class method prototypes
+ *
+ ***********************************************************************/
+
+/** Set the "MD5 signature checking" flag.
+ *  This is inherited from FLAC__SeekableStreamDecoder; see
+ *  FLAC__seekable_stream_decoder_set_md5_checking().
+ *
+ * \default \c false
+ * \param  decoder  A decoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__file_decoder_set_md5_checking(FLAC__FileDecoder *decoder, FLAC__bool value);
+
+/** Set the input file name to decode.
+ *
+ * \default \c "-"
+ * \param  decoder  A decoder instance to set.
+ * \param  value    The input file name, or "-" for \c stdin.
+ * \assert
+ *    \code decoder != NULL \endcode
+ *    \code value != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, or there was a memory
+ *    allocation error, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__file_decoder_set_filename(FLAC__FileDecoder *decoder, const char *value);
+
+/** Set the write callback.
+ *  This is inherited from FLAC__SeekableStreamDecoder; see
+ *  FLAC__seekable_stream_decoder_set_write_callback().
+ *
+ * \note
+ * The callback is mandatory and must be set before initialization.
+ *
+ * \default \c NULL
+ * \param  decoder  A decoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code decoder != NULL \endcode
+ *    \code value != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__file_decoder_set_write_callback(FLAC__FileDecoder *decoder, FLAC__FileDecoderWriteCallback value);
+
+/** Set the metadata callback.
+ *  This is inherited from FLAC__SeekableStreamDecoder; see
+ *  FLAC__seekable_stream_decoder_set_metadata_callback().
+ *
+ * \note
+ * The callback is mandatory and must be set before initialization.
+ *
+ * \default \c NULL
+ * \param  decoder  A decoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code decoder != NULL \endcode
+ *    \code value != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__file_decoder_set_metadata_callback(FLAC__FileDecoder *decoder, FLAC__FileDecoderMetadataCallback value);
+
+/** Set the error callback.
+ *  This is inherited from FLAC__SeekableStreamDecoder; see
+ *  FLAC__seekable_stream_decoder_set_error_callback().
+ *
+ * \note
+ * The callback is mandatory and must be set before initialization.
+ *
+ * \default \c NULL
+ * \param  decoder  A decoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code decoder != NULL \endcode
+ *    \code value != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__file_decoder_set_error_callback(FLAC__FileDecoder *decoder, FLAC__FileDecoderErrorCallback value);
+
+/** Set the client data to be passed back to callbacks.
+ *  This value will be supplied to callbacks in their \a client_data
+ *  argument.
+ *
+ * \default \c NULL
+ * \param  decoder  A decoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__file_decoder_set_client_data(FLAC__FileDecoder *decoder, void *value);
+
+/** This is inherited from FLAC__SeekableStreamDecoder; see
+ *  FLAC__seekable_stream_decoder_set_metadata_respond().
+ *
+ * \default By default, only the \c STREAMINFO block is returned via the
+ *          metadata callback.
+ * \param  decoder  A decoder instance to set.
+ * \param  type     See above.
+ * \assert
+ *    \code decoder != NULL \endcode
+ *    \a type is valid
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__file_decoder_set_metadata_respond(FLAC__FileDecoder *decoder, FLAC__MetadataType type);
+
+/** This is inherited from FLAC__SeekableStreamDecoder; see
+ *  FLAC__seekable_stream_decoder_set_metadata_respond_application().
+ *
+ * \default By default, only the \c STREAMINFO block is returned via the
+ *          metadata callback.
+ * \param  decoder  A decoder instance to set.
+ * \param  id       See above.
+ * \assert
+ *    \code decoder != NULL \endcode
+ *    \code id != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__file_decoder_set_metadata_respond_application(FLAC__FileDecoder *decoder, const FLAC__byte id[4]);
+
+/** This is inherited from FLAC__SeekableStreamDecoder; see
+ *  FLAC__seekable_stream_decoder_set_metadata_respond_all().
+ *
+ * \default By default, only the \c STREAMINFO block is returned via the
+ *          metadata callback.
+ * \param  decoder  A decoder instance to set.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__file_decoder_set_metadata_respond_all(FLAC__FileDecoder *decoder);
+
+/** This is inherited from FLAC__SeekableStreamDecoder; see
+ *  FLAC__seekable_stream_decoder_set_metadata_ignore().
+ *
+ * \default By default, only the \c STREAMINFO block is returned via the
+ *          metadata callback.
+ * \param  decoder  A decoder instance to set.
+ * \param  type     See above.
+ * \assert
+ *    \code decoder != NULL \endcode
+ *    \a type is valid
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__file_decoder_set_metadata_ignore(FLAC__FileDecoder *decoder, FLAC__MetadataType type);
+
+/** This is inherited from FLAC__SeekableStreamDecoder; see
+ *  FLAC__seekable_stream_decoder_set_metadata_ignore_application().
+ *
+ * \default By default, only the \c STREAMINFO block is returned via the
+ *          metadata callback.
+ * \param  decoder  A decoder instance to set.
+ * \param  id       See above.
+ * \assert
+ *    \code decoder != NULL \endcode
+ *    \code id != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__file_decoder_set_metadata_ignore_application(FLAC__FileDecoder *decoder, const FLAC__byte id[4]);
+
+/** This is inherited from FLAC__SeekableStreamDecoder; see
+ *  FLAC__seekable_stream_decoder_set_metadata_ignore_all().
+ *
+ * \default By default, only the \c STREAMINFO block is returned via the
+ *          metadata callback.
+ * \param  decoder  A decoder instance to set.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__file_decoder_set_metadata_ignore_all(FLAC__FileDecoder *decoder);
+
+/** Get the current decoder state.
+ *
+ * \param  decoder  A decoder instance to query.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__FileDecoderState
+ *    The current decoder state.
+ */
+FLAC_API FLAC__FileDecoderState FLAC__file_decoder_get_state(const FLAC__FileDecoder *decoder);
+
+/** Get the state of the underlying seekable stream decoder.
+ *  Useful when the file decoder state is
+ *  \c FLAC__FILE_DECODER_SEEKABLE_STREAM_DECODER_ERROR.
+ *
+ * \param  decoder  A decoder instance to query.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__SeekableStreamDecoderState
+ *    The seekable stream decoder state.
+ */
+FLAC_API FLAC__SeekableStreamDecoderState FLAC__file_decoder_get_seekable_stream_decoder_state(const FLAC__FileDecoder *decoder);
+
+/** Get the state of the underlying stream decoder.
+ *  Useful when the file decoder state is
+ *  \c FLAC__FILE_DECODER_SEEKABLE_STREAM_DECODER_ERROR and the seekable stream
+ *  decoder state is \c FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR.
+ *
+ * \param  decoder  A decoder instance to query.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__StreamDecoderState
+ *    The seekable stream decoder state.
+ */
+FLAC_API FLAC__StreamDecoderState FLAC__file_decoder_get_stream_decoder_state(const FLAC__FileDecoder *decoder);
+
+/** Get the current decoder state as a C string.
+ *  This version automatically resolves
+ *  \c FLAC__FILE_DECODER_SEEKABLE_STREAM_DECODER_ERROR by getting the
+ *  seekable stream decoder's state.
+ *
+ * \param  decoder  A decoder instance to query.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval const char *
+ *    The decoder state as a C string.  Do not modify the contents.
+ */
+FLAC_API const char *FLAC__file_decoder_get_resolved_state_string(const FLAC__FileDecoder *decoder);
+
+/** Get the "MD5 signature checking" flag.
+ *  This is inherited from FLAC__SeekableStreamDecoder; see
+ *  FLAC__seekable_stream_decoder_get_md5_checking().
+ *
+ * \param  decoder  A decoder instance to query.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See above.
+ */
+FLAC_API FLAC__bool FLAC__file_decoder_get_md5_checking(const FLAC__FileDecoder *decoder);
+
+/** This is inherited from FLAC__SeekableStreamDecoder; see
+ *  FLAC__seekable_stream_decoder_get_channels().
+ *
+ * \param  decoder  A decoder instance to query.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval unsigned
+ *    See above.
+ */
+FLAC_API unsigned FLAC__file_decoder_get_channels(const FLAC__FileDecoder *decoder);
+
+/** This is inherited from FLAC__SeekableStreamDecoder; see
+ *  FLAC__seekable_stream_decoder_get_channel_assignment().
+ *
+ * \param  decoder  A decoder instance to query.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__ChannelAssignment
+ *    See above.
+ */
+FLAC_API FLAC__ChannelAssignment FLAC__file_decoder_get_channel_assignment(const FLAC__FileDecoder *decoder);
+
+/** This is inherited from FLAC__SeekableStreamDecoder; see
+ *  FLAC__seekable_stream_decoder_get_bits_per_sample().
+ *
+ * \param  decoder  A decoder instance to query.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval unsigned
+ *    See above.
+ */
+FLAC_API unsigned FLAC__file_decoder_get_bits_per_sample(const FLAC__FileDecoder *decoder);
+
+/** This is inherited from FLAC__SeekableStreamDecoder; see
+ *  FLAC__seekable_stream_decoder_get_sample_rate().
+ *
+ * \param  decoder  A decoder instance to query.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval unsigned
+ *    See above.
+ */
+FLAC_API unsigned FLAC__file_decoder_get_sample_rate(const FLAC__FileDecoder *decoder);
+
+/** This is inherited from FLAC__SeekableStreamDecoder; see
+ *  FLAC__seekable_stream_decoder_get_blocksize().
+ *
+ * \param  decoder  A decoder instance to query.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval unsigned
+ *    See above.
+ */
+FLAC_API unsigned FLAC__file_decoder_get_blocksize(const FLAC__FileDecoder *decoder);
+
+/** This is inherited from FLAC__SeekableStreamDecoder; see
+ *  FLAC__seekable_stream_decoder_get_decode_position().
+ *
+ * \param  decoder   A decoder instance to query.
+ * \param  position  Address at which to return the desired position.
+ * \assert
+ *    \code decoder != NULL \endcode
+ *    \code position != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if successful, \c false if there was an error from
+ *    the 'tell' callback.
+ */
+FLAC_API FLAC__bool FLAC__file_decoder_get_decode_position(const FLAC__FileDecoder *decoder, FLAC__uint64 *position);
+
+/** Initialize the decoder instance.
+ *  Should be called after FLAC__file_decoder_new() and
+ *  FLAC__file_decoder_set_*() but before any of the
+ *  FLAC__file_decoder_process_*() functions.  Will set and return
+ *  the decoder state, which will be FLAC__FILE_DECODER_OK if
+ *  initialization succeeded.
+ *
+ * \param  decoder  An uninitialized decoder instance.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__FileDecoderState
+ *    \c FLAC__FILE_DECODER_OK if initialization was successful; see
+ *    FLAC__FileDecoderState for the meanings of other return values.
+ */
+FLAC_API FLAC__FileDecoderState FLAC__file_decoder_init(FLAC__FileDecoder *decoder);
+
+/** Finish the decoding process.
+ *  Flushes the decoding buffer, releases resources, resets the decoder
+ *  settings to their defaults, and returns the decoder state to
+ *  FLAC__FILE_DECODER_UNINITIALIZED.
+ *
+ *  In the event of a prematurely-terminated decode, it is not strictly
+ *  necessary to call this immediately before FLAC__file_decoder_delete()
+ *  but it is good practice to match every FLAC__file_decoder_init() with
+ *  a FLAC__file_decoder_finish().
+ *
+ * \param  decoder  An uninitialized decoder instance.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if MD5 checking is on AND a STREAMINFO block was available
+ *    AND the MD5 signature in the STREAMINFO block was non-zero AND the
+ *    signature does not match the one computed by the decoder; else
+ *    \c true.
+ */
+FLAC_API FLAC__bool FLAC__file_decoder_finish(FLAC__FileDecoder *decoder);
+
+/** This is inherited from FLAC__SeekableStreamDecoder; see
+ *  FLAC__seekable_stream_decoder_process_single().
+ *
+ * \param  decoder  A decoder instance.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See above.
+ */
+FLAC_API FLAC__bool FLAC__file_decoder_process_single(FLAC__FileDecoder *decoder);
+
+/** This is inherited from FLAC__SeekableStreamDecoder; see
+ *  FLAC__seekable_stream_decoder_process_until_end_of_metadata().
+ *
+ * \param  decoder  A decoder instance.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See above.
+ */
+FLAC_API FLAC__bool FLAC__file_decoder_process_until_end_of_metadata(FLAC__FileDecoder *decoder);
+
+/** This is inherited from FLAC__SeekableStreamDecoder; see
+ *  FLAC__seekable_stream_decoder_process_until_end_of_stream().
+ *
+ * \param  decoder  A decoder instance.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See above.
+ */
+FLAC_API FLAC__bool FLAC__file_decoder_process_until_end_of_file(FLAC__FileDecoder *decoder);
+
+/** This is inherited from FLAC__SeekableStreamDecoder; see
+ *  FLAC__seekable_stream_decoder_skip_single_frame().
+ *
+ * \param  decoder  A decoder instance.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See above.
+ */
+FLAC_API FLAC__bool FLAC__file_decoder_skip_single_frame(FLAC__FileDecoder *decoder);
+
+/** Flush the input and seek to an absolute sample.
+ *  This is inherited from FLAC__SeekableStreamDecoder; see
+ *  FLAC__seekable_stream_decoder_seek_absolute().
+ *
+ * \param  decoder  A decoder instance.
+ * \param  sample   The target sample number to seek to.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if successful, else \c false.
+ */
+FLAC_API FLAC__bool FLAC__file_decoder_seek_absolute(FLAC__FileDecoder *decoder, FLAC__uint64 sample);
+
+/* \} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/FLAC/file_encoder.h
@@ -1,0 +1,871 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2002,2003,2004  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__FILE_ENCODER_H
+#define FLAC__FILE_ENCODER_H
+
+#include "export.h"
+#include "seekable_stream_encoder.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** \file include/FLAC/file_encoder.h
+ *
+ *  \brief
+ *  This module contains the functions which implement the file
+ *  encoder.
+ *
+ *  See the detailed documentation in the
+ *  \link flac_file_encoder file encoder \endlink module.
+ */
+
+/** \defgroup flac_file_encoder FLAC/file_encoder.h: file encoder interface
+ *  \ingroup flac_encoder
+ *
+ *  \brief
+ *  This module contains the functions which implement the file
+ *  encoder.
+ *
+ * The basic usage of this encoder is as follows:
+ * - The program creates an instance of an encoder using
+ *   FLAC__file_encoder_new().
+ * - The program overrides the default settings using
+ *   FLAC__file_encoder_set_*() functions.
+ * - The program initializes the instance to validate the settings and
+ *   prepare for encoding using FLAC__file_encoder_init().
+ * - The program calls FLAC__file_encoder_process() or
+ *   FLAC__file_encoder_process_interleaved() to encode data, which
+ *   subsequently writes data to the output file.
+ * - The program finishes the encoding with FLAC__file_encoder_finish(),
+ *   which causes the encoder to encode any data still in its input pipe,
+ *   rewind and write the STREAMINFO metadata to file, and finally reset
+ *   the encoder to the uninitialized state.
+ * - The instance may be used again or deleted with
+ *   FLAC__file_encoder_delete().
+ *
+ * The file encoder is a wrapper around the
+ * \link flac_seekable_stream_encoder seekable stream encoder \endlink which supplies all
+ * callbacks internally; the user need specify only the filename.
+ *
+ * Make sure to read the detailed description of the
+ * \link flac_seekable_stream_encoder seekable stream encoder module \endlink since the
+ * \link flac_stream_encoder stream encoder module \endlink since the
+ * file encoder inherits much of its behavior from them.
+ *
+ * \note
+ * The "set" functions may only be called when the encoder is in the
+ * state FLAC__FILE_ENCODER_UNINITIALIZED, i.e. after
+ * FLAC__file_encoder_new() or FLAC__file_encoder_finish(), but
+ * before FLAC__file_encoder_init().  If this is the case they will
+ * return \c true, otherwise \c false.
+ *
+ * \note
+ * FLAC__file_encoder_finish() resets all settings to the constructor
+ * defaults.
+ *
+ * \{
+ */
+
+
+/** State values for a FLAC__FileEncoder
+ *
+ *  The encoder's state can be obtained by calling FLAC__file_encoder_get_state().
+ */
+typedef enum {
+
+	FLAC__FILE_ENCODER_OK = 0,
+	/**< The encoder is in the normal OK state. */
+
+	FLAC__FILE_ENCODER_NO_FILENAME,
+	/**< FLAC__file_encoder_init() was called without first calling
+	 * FLAC__file_encoder_set_filename().
+	 */
+
+	FLAC__FILE_ENCODER_SEEKABLE_STREAM_ENCODER_ERROR,
+	/**< An error occurred in the underlying seekable stream encoder;
+	 * check FLAC__file_encoder_get_seekable_stream_encoder_state().
+	 */
+
+	FLAC__FILE_ENCODER_FATAL_ERROR_WHILE_WRITING,
+	/**< A fatal error occurred while writing to the encoded file. */
+
+	FLAC__FILE_ENCODER_ERROR_OPENING_FILE,
+	/**< An error occurred opening the output file for writing. */
+
+	FLAC__FILE_ENCODER_MEMORY_ALLOCATION_ERROR,
+	/**< Memory allocation failed. */
+
+	FLAC__FILE_ENCODER_ALREADY_INITIALIZED,
+	/**< FLAC__file_encoder_init() was called when the encoder was
+	 * already initialized, usually because
+	 * FLAC__file_encoder_finish() was not called.
+	 */
+
+	FLAC__FILE_ENCODER_UNINITIALIZED
+	/**< The encoder is in the uninitialized state. */
+
+} FLAC__FileEncoderState;
+
+/** Maps a FLAC__FileEncoderState to a C string.
+ *
+ *  Using a FLAC__FileEncoderState as the index to this array
+ *  will give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__FileEncoderStateString[];
+
+
+/***********************************************************************
+ *
+ * class FLAC__FileEncoder
+ *
+ ***********************************************************************/
+
+struct FLAC__FileEncoderProtected;
+struct FLAC__FileEncoderPrivate;
+/** The opaque structure definition for the file encoder type.
+ *  See the \link flac_file_encoder file encoder module \endlink
+ *  for a detailed description.
+ */
+typedef struct {
+	struct FLAC__FileEncoderProtected *protected_; /* avoid the C++ keyword 'protected' */
+	struct FLAC__FileEncoderPrivate *private_; /* avoid the C++ keyword 'private' */
+} FLAC__FileEncoder;
+
+/** Signature for the progress callback.
+ *  See FLAC__file_encoder_set_progress_callback() for more info.
+ *
+ * \param  encoder          The encoder instance calling the callback.
+ * \param  bytes_written    Bytes written so far.
+ * \param  samples_written  Samples written so far.
+ * \param  frames_written   Frames written so far.
+ * \param  total_frames_estimate  The estimate of the total number of
+ *                                frames to be written.
+ * \param  client_data      The callee's client data set through
+ *                          FLAC__file_encoder_set_client_data().
+ */
+typedef void (*FLAC__FileEncoderProgressCallback)(const FLAC__FileEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_estimate, void *client_data);
+
+
+/***********************************************************************
+ *
+ * Class constructor/destructor
+ *
+ ***********************************************************************/
+
+/** Create a new file encoder instance.  The instance is created with
+ *  default settings; see the individual FLAC__file_encoder_set_*()
+ *  functions for each setting's default.
+ *
+ * \retval FLAC__FileEncoder*
+ *    \c NULL if there was an error allocating memory, else the new instance.
+ */
+FLAC_API FLAC__FileEncoder *FLAC__file_encoder_new();
+
+/** Free an encoder instance.  Deletes the object pointed to by \a encoder.
+ *
+ * \param encoder  A pointer to an existing encoder.
+ * \assert
+ *    \code encoder != NULL \endcode
+ */
+FLAC_API void FLAC__file_encoder_delete(FLAC__FileEncoder *encoder);
+
+/***********************************************************************
+ *
+ * Public class method prototypes
+ *
+ ***********************************************************************/
+
+/** This is inherited from FLAC__SeekableStreamEncoder; see
+ *  FLAC__seekable_stream_encoder_set_verify().
+ *
+ * \default \c true
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__file_encoder_set_verify(FLAC__FileEncoder *encoder, FLAC__bool value);
+
+/** This is inherited from FLAC__SeekableStreamEncoder; see
+ *  FLAC__seekable_stream_encoder_set_streamable_subset().
+ *
+ * \default \c true
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__file_encoder_set_streamable_subset(FLAC__FileEncoder *encoder, FLAC__bool value);
+
+/** This is inherited from FLAC__SeekableStreamEncoder; see
+ *  FLAC__seekable_stream_encoder_set_do_mid_side_stereo().
+ *
+ * \default \c false
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__file_encoder_set_do_mid_side_stereo(FLAC__FileEncoder *encoder, FLAC__bool value);
+
+/** This is inherited from FLAC__SeekableStreamEncoder; see
+ *  FLAC__seekable_stream_encoder_set_loose_mid_side_stereo().
+ *
+ * \default \c false
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__file_encoder_set_loose_mid_side_stereo(FLAC__FileEncoder *encoder, FLAC__bool value);
+
+/** This is inherited from FLAC__SeekableStreamEncoder; see
+ *  FLAC__seekable_stream_encoder_set_channels().
+ *
+ * \default \c 2
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__file_encoder_set_channels(FLAC__FileEncoder *encoder, unsigned value);
+
+/** This is inherited from FLAC__SeekableStreamEncoder; see
+ *  FLAC__seekable_stream_encoder_set_bits_per_sample().
+ *
+ * \warning
+ * Do not feed the encoder data that is wider than the value you
+ * set here or you will generate an invalid stream.
+ *
+ * \default \c 16
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__file_encoder_set_bits_per_sample(FLAC__FileEncoder *encoder, unsigned value);
+
+/** This is inherited from FLAC__SeekableStreamEncoder; see
+ *  FLAC__seekable_stream_encoder_set_sample_rate().
+ *
+ * \default \c 44100
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__file_encoder_set_sample_rate(FLAC__FileEncoder *encoder, unsigned value);
+
+/** This is inherited from FLAC__SeekableStreamEncoder; see
+ *  FLAC__seekable_stream_encoder_set_blocksize().
+ *
+ * \default \c 1152
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__file_encoder_set_blocksize(FLAC__FileEncoder *encoder, unsigned value);
+
+/** This is inherited from FLAC__SeekableStreamEncoder; see
+ *  FLAC__seekable_stream_encoder_set_max_lpc_order().
+ *
+ * \default \c 0
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__file_encoder_set_max_lpc_order(FLAC__FileEncoder *encoder, unsigned value);
+
+/** This is inherited from FLAC__SeekableStreamEncoder; see
+ *  FLAC__seekable_stream_encoder_set_qlp_coeff_precision().
+ *
+ * \note
+ * In the current implementation, qlp_coeff_precision + bits_per_sample must
+ * be less than 32.
+ *
+ * \default \c 0
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__file_encoder_set_qlp_coeff_precision(FLAC__FileEncoder *encoder, unsigned value);
+
+/** This is inherited from FLAC__SeekableStreamEncoder; see
+ *  FLAC__seekable_stream_encoder_set_do_qlp_coeff_prec_search().
+ *
+ * \default \c false
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__file_encoder_set_do_qlp_coeff_prec_search(FLAC__FileEncoder *encoder, FLAC__bool value);
+
+/** This is inherited from FLAC__SeekableStreamEncoder; see
+ *  FLAC__seekable_stream_encoder_set_do_escape_coding().
+ *
+ * \default \c false
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__file_encoder_set_do_escape_coding(FLAC__FileEncoder *encoder, FLAC__bool value);
+
+/** This is inherited from FLAC__SeekableStreamEncoder; see
+ *  FLAC__seekable_stream_encoder_set_do_exhaustive_model_search().
+ *
+ * \default \c false
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__file_encoder_set_do_exhaustive_model_search(FLAC__FileEncoder *encoder, FLAC__bool value);
+
+/** This is inherited from FLAC__SeekableStreamEncoder; see
+ *  FLAC__seekable_stream_encoder_set_min_residual_partition_order().
+ *
+ * \default \c 0
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__file_encoder_set_min_residual_partition_order(FLAC__FileEncoder *encoder, unsigned value);
+
+/** This is inherited from FLAC__SeekableStreamEncoder; see
+ *  FLAC__seekable_stream_encoder_set_max_residual_partition_order().
+ *
+ * \default \c 0
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__file_encoder_set_max_residual_partition_order(FLAC__FileEncoder *encoder, unsigned value);
+
+/** This is inherited from FLAC__SeekableStreamEncoder; see
+ *  FLAC__seekable_stream_encoder_set_rice_parameter_search_dist().
+ *
+ * \default \c 0
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__file_encoder_set_rice_parameter_search_dist(FLAC__FileEncoder *encoder, unsigned value);
+
+/** This is inherited from FLAC__SeekableStreamEncoder; see
+ *  FLAC__seekable_stream_encoder_set_total_samples_estimate().
+ *
+ * \default \c 0
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__file_encoder_set_total_samples_estimate(FLAC__FileEncoder *encoder, FLAC__uint64 value);
+
+/** This is inherited from FLAC__SeekableStreamEncoder; see
+ *  FLAC__seekable_stream_encoder_set_metadata().
+ *
+ * \default \c NULL, 0
+ * \param  encoder     An encoder instance to set.
+ * \param  metadata    See above.
+ * \param  num_blocks  See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__file_encoder_set_metadata(FLAC__FileEncoder *encoder, FLAC__StreamMetadata **metadata, unsigned num_blocks);
+
+/** Set the output file name encode to.
+ *
+ * \note
+ * The filename is mandatory and must be set before initialization.
+ *
+ * \note
+ * Unlike the FLAC__FileDecoder, the filename does not interpret "-" for
+ * \c stdout; writing to \c stdout is not relevant in the file encoder.
+ *
+ * \default \c NULL
+ * \param  encoder  A encoder instance to set.
+ * \param  value    The output file name.
+ * \assert
+ *    \code encoder != NULL \endcode
+ *    \code value != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, or there was a memory
+ *    allocation error, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__file_encoder_set_filename(FLAC__FileEncoder *encoder, const char *value);
+
+/** Set the progress callback.
+ *  The supplied function will be called when the encoder has finished
+ *  writing a frame.  The \c total_frames_estimate argument to the callback
+ *  will be based on the value from
+ *  FLAC__file_encoder_set_total_samples_estimate().
+ *
+ * \note
+ * Unlike most other callbacks, the progress callback is \b not mandatory
+ * and need not be set before initialization.
+ *
+ * \default \c NULL
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ *    \code value != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__file_encoder_set_progress_callback(FLAC__FileEncoder *encoder, FLAC__FileEncoderProgressCallback value);
+
+/** Set the client data to be passed back to callbacks.
+ *  This value will be supplied to callbacks in their \a client_data
+ *  argument.
+ *
+ * \default \c NULL
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__file_encoder_set_client_data(FLAC__FileEncoder *encoder, void *value);
+
+/** Get the current encoder state.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__FileEncoderState
+ *    The current encoder state.
+ */
+FLAC_API FLAC__FileEncoderState FLAC__file_encoder_get_state(const FLAC__FileEncoder *encoder);
+
+/** Get the state of the underlying seekable stream encoder.
+ *  Useful when the file encoder state is
+ *  \c FLAC__FILE_ENCODER_SEEKABLE_STREAM_ENCODER_ERROR.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__SeekableStreamEncoderState
+ *    The seekable stream encoder state.
+ */
+FLAC_API FLAC__SeekableStreamEncoderState FLAC__file_encoder_get_seekable_stream_encoder_state(const FLAC__FileEncoder *encoder);
+
+/** Get the state of the underlying stream encoder.
+ *  Useful when the file encoder state is
+ *  \c FLAC__FILE_ENCODER_SEEKABLE_STREAM_ENCODER_ERROR and the seekable stream
+ *  encoder state is \c FLAC__SEEKABLE_STREAM_ENCODER_STREAM_ENCODER_ERROR.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__StreamEncoderState
+ *    The seekable stream encoder state.
+ */
+FLAC_API FLAC__StreamEncoderState FLAC__file_encoder_get_stream_encoder_state(const FLAC__FileEncoder *encoder);
+
+/** Get the state of the underlying stream encoder's verify decoder.
+ *  Useful when the file encoder state is
+ *  \c FLAC__FILE_ENCODER_SEEKABLE_STREAM_ENCODER_ERROR and the seekable stream
+ *  encoder state is \c FLAC__SEEKABLE_STREAM_ENCODER_STREAM_ENCODER_ERROR and
+ *  the stream encoder state is \c FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__StreamDecoderState
+ *    The stream encoder state.
+ */
+FLAC_API FLAC__StreamDecoderState FLAC__file_encoder_get_verify_decoder_state(const FLAC__FileEncoder *encoder);
+
+/** Get the current encoder state as a C string.
+ *  This version automatically resolves
+ *  \c FLAC__FILE_ENCODER_SEEKABLE_STREAM_ENCODER_ERROR by getting the
+ *  seekable stream encoder's state.
+ *
+ * \param  encoder  A encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval const char *
+ *    The encoder state as a C string.  Do not modify the contents.
+ */
+FLAC_API const char *FLAC__file_encoder_get_resolved_state_string(const FLAC__FileEncoder *encoder);
+
+/** Get relevant values about the nature of a verify decoder error.
+ *  Inherited from FLAC__seekable_stream_encoder_get_verify_decoder_error_stats().
+ *  Useful when the file encoder state is
+ *  \c FLAC__FILE_ENCODER_SEEKABLE_STREAM_ENCODER_ERROR and the seekable stream
+ *  encoder state is
+ *  \c FLAC__SEEKABLE_STREAM_ENCODER_STREAM_ENCODER_ERROR and the
+ *  stream encoder state is
+ *  \c FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \param  absolute_sample  The absolute sample number of the mismatch.
+ * \param  frame_number  The number of the frame in which the mismatch occurred.
+ * \param  channel       The channel in which the mismatch occurred.
+ * \param  sample        The number of the sample (relative to the frame) in
+ *                       which the mismatch occurred.
+ * \param  expected      The expected value for the sample in question.
+ * \param  got           The actual value returned by the decoder.
+ * \assert
+ *    \code encoder != NULL \endcode
+ */
+FLAC_API void FLAC__file_encoder_get_verify_decoder_error_stats(const FLAC__FileEncoder *encoder, FLAC__uint64 *absolute_sample, unsigned *frame_number, unsigned *channel, unsigned *sample, FLAC__int32 *expected, FLAC__int32 *got);
+
+/** Get the "verify" flag.
+ *  This is inherited from FLAC__SeekableStreamEncoder; see
+ *  FLAC__seekable_stream_encoder_get_verify().
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See FLAC__file_encoder_set_verify().
+ */
+FLAC_API FLAC__bool FLAC__file_encoder_get_verify(const FLAC__FileEncoder *encoder);
+
+/** Get the "streamable subset" flag.
+ *  This is inherited from FLAC__SeekableStreamEncoder; see
+ *  FLAC__seekable_stream_encoder_get_streamable_subset().
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See FLAC__file_encoder_set_streamable_subset().
+ */
+FLAC_API FLAC__bool FLAC__file_encoder_get_streamable_subset(const FLAC__FileEncoder *encoder);
+
+/** Get the "mid/side stereo coding" flag.
+ *  This is inherited from FLAC__SeekableStreamEncoder; see
+ *  FLAC__seekable_stream_encoder_get_do_mid_side_stereo().
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See FLAC__file_encoder_get_do_mid_side_stereo().
+ */
+FLAC_API FLAC__bool FLAC__file_encoder_get_do_mid_side_stereo(const FLAC__FileEncoder *encoder);
+
+/** Get the "adaptive mid/side switching" flag.
+ *  This is inherited from FLAC__SeekableStreamEncoder; see
+ *  FLAC__seekable_stream_encoder_get_loose_mid_side_stereo().
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See FLAC__file_encoder_set_loose_mid_side_stereo().
+ */
+FLAC_API FLAC__bool FLAC__file_encoder_get_loose_mid_side_stereo(const FLAC__FileEncoder *encoder);
+
+/** Get the number of input channels being processed.
+ *  This is inherited from FLAC__SeekableStreamEncoder; see
+ *  FLAC__seekable_stream_encoder_get_channels().
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval unsigned
+ *    See FLAC__file_encoder_set_channels().
+ */
+FLAC_API unsigned FLAC__file_encoder_get_channels(const FLAC__FileEncoder *encoder);
+
+/** Get the input sample resolution setting.
+ *  This is inherited from FLAC__SeekableStreamEncoder; see
+ *  FLAC__seekable_stream_encoder_get_bits_per_sample().
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval unsigned
+ *    See FLAC__file_encoder_set_bits_per_sample().
+ */
+FLAC_API unsigned FLAC__file_encoder_get_bits_per_sample(const FLAC__FileEncoder *encoder);
+
+/** Get the input sample rate setting.
+ *  This is inherited from FLAC__SeekableStreamEncoder; see
+ *  FLAC__seekable_stream_encoder_get_sample_rate().
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval unsigned
+ *    See FLAC__file_encoder_set_sample_rate().
+ */
+FLAC_API unsigned FLAC__file_encoder_get_sample_rate(const FLAC__FileEncoder *encoder);
+
+/** Get the blocksize setting.
+ *  This is inherited from FLAC__SeekableStreamEncoder; see
+ *  FLAC__seekable_stream_encoder_get_blocksize().
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval unsigned
+ *    See FLAC__file_encoder_set_blocksize().
+ */
+FLAC_API unsigned FLAC__file_encoder_get_blocksize(const FLAC__FileEncoder *encoder);
+
+/** Get the maximum LPC order setting.
+ *  This is inherited from FLAC__SeekableStreamEncoder; see
+ *  FLAC__seekable_stream_encoder_get_max_lpc_order().
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval unsigned
+ *    See FLAC__file_encoder_set_max_lpc_order().
+ */
+FLAC_API unsigned FLAC__file_encoder_get_max_lpc_order(const FLAC__FileEncoder *encoder);
+
+/** Get the quantized linear predictor coefficient precision setting.
+ *  This is inherited from FLAC__SeekableStreamEncoder; see
+ *  FLAC__seekable_stream_encoder_get_qlp_coeff_precision().
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval unsigned
+ *    See FLAC__file_encoder_set_qlp_coeff_precision().
+ */
+FLAC_API unsigned FLAC__file_encoder_get_qlp_coeff_precision(const FLAC__FileEncoder *encoder);
+
+/** Get the qlp coefficient precision search flag.
+ *  This is inherited from FLAC__SeekableStreamEncoder; see
+ *  FLAC__seekable_stream_encoder_get_do_qlp_coeff_prec_search().
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See FLAC__file_encoder_set_do_qlp_coeff_prec_search().
+ */
+FLAC_API FLAC__bool FLAC__file_encoder_get_do_qlp_coeff_prec_search(const FLAC__FileEncoder *encoder);
+
+/** Get the "escape coding" flag.
+ *  This is inherited from FLAC__SeekableStreamEncoder; see
+ *  FLAC__seekable_stream_encoder_get_do_escape_coding().
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See FLAC__file_encoder_set_do_escape_coding().
+ */
+FLAC_API FLAC__bool FLAC__file_encoder_get_do_escape_coding(const FLAC__FileEncoder *encoder);
+
+/** Get the exhaustive model search flag.
+ *  This is inherited from FLAC__SeekableStreamEncoder; see
+ *  FLAC__seekable_stream_encoder_get_do_exhaustive_model_search().
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See FLAC__file_encoder_set_do_exhaustive_model_search().
+ */
+FLAC_API FLAC__bool FLAC__file_encoder_get_do_exhaustive_model_search(const FLAC__FileEncoder *encoder);
+
+/** Get the minimum residual partition order setting.
+ *  This is inherited from FLAC__SeekableStreamEncoder; see
+ *  FLAC__seekable_stream_encoder_get_min_residual_partition_order().
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval unsigned
+ *    See FLAC__file_encoder_set_min_residual_partition_order().
+ */
+FLAC_API unsigned FLAC__file_encoder_get_min_residual_partition_order(const FLAC__FileEncoder *encoder);
+
+/** Get maximum residual partition order setting.
+ *  This is inherited from FLAC__SeekableStreamEncoder; see
+ *  FLAC__seekable_stream_encoder_get_max_residual_partition_order().
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval unsigned
+ *    See FLAC__file_encoder_set_max_residual_partition_order().
+ */
+FLAC_API unsigned FLAC__file_encoder_get_max_residual_partition_order(const FLAC__FileEncoder *encoder);
+
+/** Get the Rice parameter search distance setting.
+ *  This is inherited from FLAC__SeekableStreamEncoder; see
+ *  FLAC__seekable_stream_encoder_get_rice_parameter_search_dist().
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval unsigned
+ *    See FLAC__file_encoder_set_rice_parameter_search_dist().
+ */
+FLAC_API unsigned FLAC__file_encoder_get_rice_parameter_search_dist(const FLAC__FileEncoder *encoder);
+
+/** Get the previously set estimate of the total samples to be encoded.
+ *  This is inherited from FLAC__SeekableStreamEncoder; see
+ *  FLAC__seekable_stream_encoder_get_total_samples_estimate().
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__uint64
+ *    See FLAC__file_encoder_set_total_samples_estimate().
+ */
+FLAC_API FLAC__uint64 FLAC__file_encoder_get_total_samples_estimate(const FLAC__FileEncoder *encoder);
+
+/** Initialize the encoder instance.
+ *  Should be called after FLAC__file_encoder_new() and
+ *  FLAC__file_encoder_set_*() but before FLAC__file_encoder_process()
+ *  or FLAC__file_encoder_process_interleaved().  Will set and return
+ *  the encoder state, which will be FLAC__FILE_ENCODER_OK if
+ *  initialization succeeded.
+ *
+ * \param  encoder  An uninitialized encoder instance.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__FileEncoderState
+ *    \c FLAC__FILE_ENCODER_OK if initialization was successful; see
+ *    FLAC__FileEncoderState for the meanings of other return values.
+ */
+FLAC_API FLAC__FileEncoderState FLAC__file_encoder_init(FLAC__FileEncoder *encoder);
+
+/** Finish the encoding process.
+ *  Flushes the encoding buffer, releases resources, resets the encoder
+ *  settings to their defaults, and returns the encoder state to
+ *  FLAC__FILE_ENCODER_UNINITIALIZED.
+ *
+ *  In the event of a prematurely-terminated encode, it is not strictly
+ *  necessary to call this immediately before FLAC__file_encoder_delete()
+ *  but it is good practice to match every FLAC__file_encoder_init()
+ *  with a FLAC__file_encoder_finish().
+ *
+ * \param  encoder  An uninitialized encoder instance.
+ * \assert
+ *    \code encoder != NULL \endcode
+ */
+FLAC_API void FLAC__file_encoder_finish(FLAC__FileEncoder *encoder);
+
+/** Submit data for encoding.
+ *  This is inherited from FLAC__SeekableStreamEncoder; see
+ *  FLAC__seekable_stream_encoder_process().
+ *
+ * \param  encoder  An initialized encoder instance in the OK state.
+ * \param  buffer   An array of pointers to each channel's signal.
+ * \param  samples  The number of samples in one channel.
+ * \assert
+ *    \code encoder != NULL \endcode
+ *    \code FLAC__file_encoder_get_state(encoder) == FLAC__FILE_ENCODER_OK \endcode
+ * \retval FLAC__bool
+ *    \c true if successful, else \c false; in this case, check the
+ *    encoder state with FLAC__file_encoder_get_state() to see what
+ *    went wrong.
+ */
+FLAC_API FLAC__bool FLAC__file_encoder_process(FLAC__FileEncoder *encoder, const FLAC__int32 * const buffer[], unsigned samples);
+
+/** Submit data for encoding.
+ *  This is inherited from FLAC__SeekableStreamEncoder; see
+ *  FLAC__seekable_stream_encoder_process_interleaved().
+ *
+ * \param  encoder  An initialized encoder instance in the OK state.
+ * \param  buffer   An array of channel-interleaved data (see above).
+ * \param  samples  The number of samples in one channel, the same as for
+ *                  FLAC__file_encoder_process().  For example, if
+ *                  encoding two channels, \c 1000 \a samples corresponds
+ *                  to a \a buffer of 2000 values.
+ * \assert
+ *    \code encoder != NULL \endcode
+ *    \code FLAC__file_encoder_get_state(encoder) == FLAC__FILE_ENCODER_OK \endcode
+ * \retval FLAC__bool
+ *    \c true if successful, else \c false; in this case, check the
+ *    encoder state with FLAC__file_encoder_get_state() to see what
+ *    went wrong.
+ */
+FLAC_API FLAC__bool FLAC__file_encoder_process_interleaved(FLAC__FileEncoder *encoder, const FLAC__int32 buffer[], unsigned samples);
+
+/* \} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/FLAC/format.h
@@ -1,0 +1,812 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__FORMAT_H
+#define FLAC__FORMAT_H
+
+#include "export.h"
+#include "ordinals.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file include/FLAC/format.h
+ *
+ *  \brief
+ *  This module contains structure definitions for the representation
+ *  of FLAC format components in memory.  These are the basic
+ *  structures used by the rest of the interfaces.
+ *
+ *  See the detailed documentation in the
+ *  \link flac_format format \endlink module.
+ */
+
+/** \defgroup flac_format FLAC/format.h: format components
+ *  \ingroup flac
+ *
+ *  \brief
+ *  This module contains structure definitions for the representation
+ *  of FLAC format components in memory.  These are the basic
+ *  structures used by the rest of the interfaces.
+ *
+ *  First, you should be familiar with the
+ *  <A HREF="../format.html">FLAC format</A>.  Many of the values here
+ *  follow directly from the specification.  As a user of libFLAC, the
+ *  interesting parts really are the structures that describe the frame
+ *  header and metadata blocks.
+ *
+ *  The format structures here are very primitive, designed to store
+ *  information in an efficient way.  Reading information from the
+ *  structures is easy but creating or modifying them directly is
+ *  more complex.  For the most part, as a user of a library, editing
+ *  is not necessary; however, for metadata blocks it is, so there are
+ *  convenience functions provided in the \link flac_metadata metadata
+ *  module \endlink to simplify the manipulation of metadata blocks.
+ *
+ * \note
+ * It's not the best convention, but symbols ending in _LEN are in bits
+ * and _LENGTH are in bytes.  _LENGTH symbols are \#defines instead of
+ * global variables because they are usually used when declaring byte
+ * arrays and some compilers require compile-time knowledge of array
+ * sizes when declared on the stack.
+ *
+ * \{
+ */
+
+
+/*
+	Most of the values described in this file are defined by the FLAC
+	format specification.  There is nothing to tune here.
+*/
+
+/** The largest legal metadata type code. */
+#define FLAC__MAX_METADATA_TYPE_CODE (126u)
+
+/** The minimum block size, in samples, permitted by the format. */
+#define FLAC__MIN_BLOCK_SIZE (16u)
+
+/** The maximum block size, in samples, permitted by the format. */
+#define FLAC__MAX_BLOCK_SIZE (65535u)
+
+/** The maximum number of channels permitted by the format. */
+#define FLAC__MAX_CHANNELS (8u)
+
+/** The minimum sample resolution permitted by the format. */
+#define FLAC__MIN_BITS_PER_SAMPLE (4u)
+
+/** The maximum sample resolution permitted by the format. */
+#define FLAC__MAX_BITS_PER_SAMPLE (32u)
+
+/** The maximum sample resolution permitted by libFLAC.
+ *
+ * \warning
+ * FLAC__MAX_BITS_PER_SAMPLE is the limit of the FLAC format.  However,
+ * the reference encoder/decoder is currently limited to 24 bits because
+ * of prevalent 32-bit math, so make sure and use this value when
+ * appropriate.
+ */
+#define FLAC__REFERENCE_CODEC_MAX_BITS_PER_SAMPLE (24u)
+
+/** The maximum sample rate permitted by the format.  The value is
+ *  ((2 ^ 16) - 1) * 10; see <A HREF="../format.html">FLAC format</A>
+ *  as to why.
+ */
+#define FLAC__MAX_SAMPLE_RATE (655350u)
+
+/** The maximum LPC order permitted by the format. */
+#define FLAC__MAX_LPC_ORDER (32u)
+
+/** The minimum quantized linear predictor coefficient precision
+ *  permitted by the format.
+ */
+#define FLAC__MIN_QLP_COEFF_PRECISION (5u)
+
+/** The maximum quantized linear predictor coefficient precision
+ *  permitted by the format.
+ */
+#define FLAC__MAX_QLP_COEFF_PRECISION (15u)
+
+/** The maximum order of the fixed predictors permitted by the format. */
+#define FLAC__MAX_FIXED_ORDER (4u)
+
+/** The maximum Rice partition order permitted by the format. */
+#define FLAC__MAX_RICE_PARTITION_ORDER (15u)
+
+/** The maximum Rice partition order permitted by the FLAC Subset. */
+#define FLAC__SUBSET_MAX_RICE_PARTITION_ORDER (8u)
+
+/** The version string of the release, stamped onto the libraries and binaries.
+ *
+ * \note
+ * This does not correspond to the shared library version number, which
+ * is used to determine binary compatibility.
+ */
+extern FLAC_API const char *FLAC__VERSION_STRING;
+
+/** The vendor string inserted by the encoder into the VORBIS_COMMENT block.
+ *  This is a nulL-terminated ASCII string; when inserted into the
+ *  VORBIS_COMMENT the trailing null is stripped.
+ */
+extern FLAC_API const char *FLAC__VENDOR_STRING;
+
+/** The byte string representation of the beginning of a FLAC stream. */
+extern FLAC_API const FLAC__byte FLAC__STREAM_SYNC_STRING[4]; /* = "fLaC" */
+
+/** The 32-bit integer big-endian representation of the beginning of
+ *  a FLAC stream.
+ */
+extern FLAC_API const unsigned FLAC__STREAM_SYNC; /* = 0x664C6143 */
+
+/** The length of the FLAC signature in bits. */
+extern FLAC_API const unsigned FLAC__STREAM_SYNC_LEN; /* = 32 bits */
+
+/** The length of the FLAC signature in bytes. */
+#define FLAC__STREAM_SYNC_LENGTH (4u)
+
+
+/*****************************************************************************
+ *
+ * Subframe structures
+ *
+ *****************************************************************************/
+
+/*****************************************************************************/
+
+/** An enumeration of the available entropy coding methods. */
+typedef enum {
+	FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE = 0
+	/**< Residual is coded by partitioning into contexts, each with it's own
+	 * Rice parameter. */
+} FLAC__EntropyCodingMethodType;
+
+/** Maps a FLAC__EntropyCodingMethodType to a C string.
+ *
+ *  Using a FLAC__EntropyCodingMethodType as the index to this array will
+ *  give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__EntropyCodingMethodTypeString[];
+
+
+/** Contents of a Rice partitioned residual
+ */
+typedef struct {
+
+	unsigned *parameters;
+	/**< The Rice parameters for each context. */
+
+	unsigned *raw_bits;
+	/**< Widths for escape-coded partitions. */
+
+	unsigned capacity_by_order;
+	/**< The capacity of the \a parameters and \a raw_bits arrays
+	 * specified as an order, i.e. the number of array elements
+	 * allocated is 2 ^ \a capacity_by_order.
+	 */
+} FLAC__EntropyCodingMethod_PartitionedRiceContents;
+
+/** Header for a Rice partitioned residual.  (c.f. <A HREF="../format.html#partitioned_rice">format specification</A>)
+ */
+typedef struct {
+
+	unsigned order;
+	/**< The partition order, i.e. # of contexts = 2 ^ \a order. */
+
+	const FLAC__EntropyCodingMethod_PartitionedRiceContents *contents;
+	/**< The context's Rice parameters and/or raw bits. */
+
+} FLAC__EntropyCodingMethod_PartitionedRice;
+
+extern FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN; /**< == 4 (bits) */
+extern FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN; /**< == 4 (bits) */
+extern FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN; /**< == 5 (bits) */
+
+extern FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER;
+/**< == (1<<FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN)-1 */
+
+/** Header for the entropy coding method.  (c.f. <A HREF="../format.html#residual">format specification</A>)
+ */
+typedef struct {
+	FLAC__EntropyCodingMethodType type;
+	union {
+		FLAC__EntropyCodingMethod_PartitionedRice partitioned_rice;
+	} data;
+} FLAC__EntropyCodingMethod;
+
+extern FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_TYPE_LEN; /**< == 2 (bits) */
+
+/*****************************************************************************/
+
+/** An enumeration of the available subframe types. */
+typedef enum {
+	FLAC__SUBFRAME_TYPE_CONSTANT = 0, /**< constant signal */
+	FLAC__SUBFRAME_TYPE_VERBATIM = 1, /**< uncompressed signal */
+	FLAC__SUBFRAME_TYPE_FIXED = 2, /**< fixed polynomial prediction */
+	FLAC__SUBFRAME_TYPE_LPC = 3 /**< linear prediction */
+} FLAC__SubframeType;
+
+/** Maps a FLAC__SubframeType to a C string.
+ *
+ *  Using a FLAC__SubframeType as the index to this array will
+ *  give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__SubframeTypeString[];
+
+
+/** CONSTANT subframe.  (c.f. <A HREF="../format.html#subframe_constant">format specification</A>)
+ */
+typedef struct {
+	FLAC__int32 value; /**< The constant signal value. */
+} FLAC__Subframe_Constant;
+
+
+/** VERBATIM subframe.  (c.f. <A HREF="../format.html#subframe_verbatim">format specification</A>)
+ */
+typedef struct {
+	const FLAC__int32 *data; /**< A pointer to verbatim signal. */
+} FLAC__Subframe_Verbatim;
+
+
+/** FIXED subframe.  (c.f. <A HREF="../format.html#subframe_fixed">format specification</A>)
+ */
+typedef struct {
+	FLAC__EntropyCodingMethod entropy_coding_method;
+	/**< The residual coding method. */
+
+	unsigned order;
+	/**< The polynomial order. */
+
+	FLAC__int32 warmup[FLAC__MAX_FIXED_ORDER];
+	/**< Warmup samples to prime the predictor, length == order. */
+
+	const FLAC__int32 *residual;
+	/**< The residual signal, length == (blocksize minus order) samples. */
+} FLAC__Subframe_Fixed;
+
+
+/** LPC subframe.  (c.f. <A HREF="../format.html#subframe_lpc">format specification</A>)
+ */
+typedef struct {
+	FLAC__EntropyCodingMethod entropy_coding_method;
+	/**< The residual coding method. */
+
+	unsigned order;
+	/**< The FIR order. */
+
+	unsigned qlp_coeff_precision;
+	/**< Quantized FIR filter coefficient precision in bits. */
+
+	int quantization_level;
+	/**< The qlp coeff shift needed. */
+
+	FLAC__int32 qlp_coeff[FLAC__MAX_LPC_ORDER];
+	/**< FIR filter coefficients. */
+
+	FLAC__int32 warmup[FLAC__MAX_LPC_ORDER];
+	/**< Warmup samples to prime the predictor, length == order. */
+
+	const FLAC__int32 *residual;
+	/**< The residual signal, length == (blocksize minus order) samples. */
+} FLAC__Subframe_LPC;
+
+extern FLAC_API const unsigned FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN; /**< == 4 (bits) */
+extern FLAC_API const unsigned FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN; /**< == 5 (bits) */
+
+
+/** FLAC subframe structure.  (c.f. <A HREF="../format.html#subframe">format specification</A>)
+ */
+typedef struct {
+	FLAC__SubframeType type;
+	union {
+		FLAC__Subframe_Constant constant;
+		FLAC__Subframe_Fixed fixed;
+		FLAC__Subframe_LPC lpc;
+		FLAC__Subframe_Verbatim verbatim;
+	} data;
+	unsigned wasted_bits;
+} FLAC__Subframe;
+
+extern FLAC_API const unsigned FLAC__SUBFRAME_ZERO_PAD_LEN; /**< == 1 (bit) */
+extern FLAC_API const unsigned FLAC__SUBFRAME_TYPE_LEN; /**< == 6 (bits) */
+extern FLAC_API const unsigned FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN; /**< == 1 (bit) */
+
+extern FLAC_API const unsigned FLAC__SUBFRAME_TYPE_CONSTANT_BYTE_ALIGNED_MASK; /* = 0x00 */
+extern FLAC_API const unsigned FLAC__SUBFRAME_TYPE_VERBATIM_BYTE_ALIGNED_MASK; /* = 0x02 */
+extern FLAC_API const unsigned FLAC__SUBFRAME_TYPE_FIXED_BYTE_ALIGNED_MASK; /* = 0x10 */
+extern FLAC_API const unsigned FLAC__SUBFRAME_TYPE_LPC_BYTE_ALIGNED_MASK; /* = 0x40 */
+
+/*****************************************************************************/
+
+
+/*****************************************************************************
+ *
+ * Frame structures
+ *
+ *****************************************************************************/
+
+/** An enumeration of the available channel assignments. */
+typedef enum {
+	FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT = 0, /**< independent channels */
+	FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE = 1, /**< left+side stereo */
+	FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE = 2, /**< right+side stereo */
+	FLAC__CHANNEL_ASSIGNMENT_MID_SIDE = 3 /**< mid+side stereo */
+} FLAC__ChannelAssignment;
+
+/** Maps a FLAC__ChannelAssignment to a C string.
+ *
+ *  Using a FLAC__ChannelAssignment as the index to this array will
+ *  give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__ChannelAssignmentString[];
+
+/** An enumeration of the possible frame numbering methods. */
+typedef enum {
+	FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER, /**< number contains the frame number */
+	FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER /**< number contains the sample number of first sample in frame */
+} FLAC__FrameNumberType;
+
+/** Maps a FLAC__FrameNumberType to a C string.
+ *
+ *  Using a FLAC__FrameNumberType as the index to this array will
+ *  give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__FrameNumberTypeString[];
+
+
+/** FLAC frame header structure.  (c.f. <A HREF="../format.html#frame_header">format specification</A>)
+ */
+typedef struct {
+	unsigned blocksize;
+	/**< The number of samples per subframe. */
+
+	unsigned sample_rate;
+	/**< The sample rate in Hz. */
+
+	unsigned channels;
+	/**< The number of channels (== number of subframes). */
+
+	FLAC__ChannelAssignment channel_assignment;
+	/**< The channel assignment for the frame. */
+
+	unsigned bits_per_sample;
+	/**< The sample resolution. */
+
+	FLAC__FrameNumberType number_type;
+	/**< The numbering scheme used for the frame. */
+
+	union {
+		FLAC__uint32 frame_number;
+		FLAC__uint64 sample_number;
+	} number;
+	/**< The frame number or sample number of first sample in frame;
+	 * use the \a number_type value to determine which to use. */
+
+	FLAC__uint8 crc;
+	/**< CRC-8 (polynomial = x^8 + x^2 + x^1 + x^0, initialized with 0)
+	 * of the raw frame header bytes, meaning everything before the CRC byte
+	 * including the sync code.
+	 */
+} FLAC__FrameHeader;
+
+extern FLAC_API const unsigned FLAC__FRAME_HEADER_SYNC; /**< == 0x3ffe; the frame header sync code */
+extern FLAC_API const unsigned FLAC__FRAME_HEADER_SYNC_LEN; /**< == 14 (bits) */
+extern FLAC_API const unsigned FLAC__FRAME_HEADER_RESERVED_LEN; /**< == 2 (bits) */
+extern FLAC_API const unsigned FLAC__FRAME_HEADER_BLOCK_SIZE_LEN; /**< == 4 (bits) */
+extern FLAC_API const unsigned FLAC__FRAME_HEADER_SAMPLE_RATE_LEN; /**< == 4 (bits) */
+extern FLAC_API const unsigned FLAC__FRAME_HEADER_CHANNEL_ASSIGNMENT_LEN; /**< == 4 (bits) */
+extern FLAC_API const unsigned FLAC__FRAME_HEADER_BITS_PER_SAMPLE_LEN; /**< == 3 (bits) */
+extern FLAC_API const unsigned FLAC__FRAME_HEADER_ZERO_PAD_LEN; /**< == 1 (bit) */
+extern FLAC_API const unsigned FLAC__FRAME_HEADER_CRC_LEN; /**< == 8 (bits) */
+
+
+/** FLAC frame footer structure.  (c.f. <A HREF="../format.html#frame_footer">format specification</A>)
+ */
+typedef struct {
+	FLAC__uint16 crc;
+	/**< CRC-16 (polynomial = x^16 + x^15 + x^2 + x^0, initialized with
+	 * 0) of the bytes before the crc, back to and including the frame header
+	 * sync code.
+	 */
+} FLAC__FrameFooter;
+
+extern FLAC_API const unsigned FLAC__FRAME_FOOTER_CRC_LEN; /**< == 16 (bits) */
+
+
+/** FLAC frame structure.  (c.f. <A HREF="../format.html#frame">format specification</A>)
+ */
+typedef struct {
+	FLAC__FrameHeader header;
+	FLAC__Subframe subframes[FLAC__MAX_CHANNELS];
+	FLAC__FrameFooter footer;
+} FLAC__Frame;
+
+/*****************************************************************************/
+
+
+/*****************************************************************************
+ *
+ * Meta-data structures
+ *
+ *****************************************************************************/
+
+/** An enumeration of the available metadata block types. */
+typedef enum {
+
+	FLAC__METADATA_TYPE_STREAMINFO = 0,
+	/**< <A HREF="../format.html#metadata_block_streaminfo">STREAMINFO</A> block */
+
+	FLAC__METADATA_TYPE_PADDING = 1,
+	/**< <A HREF="../format.html#metadata_block_padding">PADDING</A> block */
+
+	FLAC__METADATA_TYPE_APPLICATION = 2,
+	/**< <A HREF="../format.html#metadata_block_application">APPLICATION</A> block */
+
+	FLAC__METADATA_TYPE_SEEKTABLE = 3,
+	/**< <A HREF="../format.html#metadata_block_seektable">SEEKTABLE</A> block */
+
+	FLAC__METADATA_TYPE_VORBIS_COMMENT = 4,
+	/**< <A HREF="../format.html#metadata_block_vorbis_comment">VORBISCOMMENT</A> block */
+
+	FLAC__METADATA_TYPE_CUESHEET = 5,
+	/**< <A HREF="../format.html#metadata_block_cuesheet">CUESHEET</A> block */
+
+	FLAC__METADATA_TYPE_UNDEFINED = 6
+	/**< marker to denote beginning of undefined type range; this number will increase as new metadata types are added */
+
+} FLAC__MetadataType;
+
+/** Maps a FLAC__MetadataType to a C string.
+ *
+ *  Using a FLAC__MetadataType as the index to this array will
+ *  give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__MetadataTypeString[];
+
+
+/** FLAC STREAMINFO structure.  (c.f. <A HREF="../format.html#metadata_block_streaminfo">format specification</A>)
+ */
+typedef struct {
+	unsigned min_blocksize, max_blocksize;
+	unsigned min_framesize, max_framesize;
+	unsigned sample_rate;
+	unsigned channels;
+	unsigned bits_per_sample;
+	FLAC__uint64 total_samples;
+	FLAC__byte md5sum[16];
+} FLAC__StreamMetadata_StreamInfo;
+
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN; /**< == 16 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN; /**< == 16 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN; /**< == 24 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN; /**< == 24 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN; /**< == 20 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN; /**< == 3 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN; /**< == 5 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN; /**< == 36 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MD5SUM_LEN; /**< == 128 (bits) */
+
+/** The total stream length of the STREAMINFO block in bytes. */
+#define FLAC__STREAM_METADATA_STREAMINFO_LENGTH (34u)
+
+/** FLAC PADDING structure.  (c.f. <A HREF="../format.html#metadata_block_padding">format specification</A>)
+ */
+typedef struct {
+	int dummy;
+	/**< Conceptually this is an empty struct since we don't store the
+	 * padding bytes.  Empty structs are not allowed by some C compilers,
+	 * hence the dummy.
+	 */
+} FLAC__StreamMetadata_Padding;
+
+
+/** FLAC APPLICATION structure.  (c.f. <A HREF="../format.html#metadata_block_application">format specification</A>)
+ */
+typedef struct {
+	FLAC__byte id[4];
+	FLAC__byte *data;
+} FLAC__StreamMetadata_Application;
+
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_APPLICATION_ID_LEN; /**< == 32 (bits) */
+
+/** SeekPoint structure used in SEEKTABLE blocks.  (c.f. <A HREF="../format.html#seekpoint">format specification</A>)
+ */
+typedef struct {
+	FLAC__uint64 sample_number;
+	/**<  The sample number of the target frame. */
+
+	FLAC__uint64 stream_offset;
+	/**< The offset, in bytes, of the target frame with respect to
+	 * beginning of the first frame. */
+
+	unsigned frame_samples;
+	/**< The number of samples in the target frame. */
+} FLAC__StreamMetadata_SeekPoint;
+
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN; /**< == 64 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN; /**< == 64 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN; /**< == 16 (bits) */
+
+/** The total stream length of a seek point in bytes. */
+#define FLAC__STREAM_METADATA_SEEKPOINT_LENGTH (18u)
+
+/** The value used in the \a sample_number field of
+ *  FLAC__StreamMetadataSeekPoint used to indicate a placeholder
+ *  point (== 0xffffffffffffffff).
+ */
+extern FLAC_API const FLAC__uint64 FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
+
+
+/** FLAC SEEKTABLE structure.  (c.f. <A HREF="../format.html#metadata_block_seektable">format specification</A>)
+ *
+ * \note From the format specification:
+ * - The seek points must be sorted by ascending sample number.
+ * - Each seek point's sample number must be the first sample of the
+ *   target frame.
+ * - Each seek point's sample number must be unique within the table.
+ * - Existence of a SEEKTABLE block implies a correct setting of
+ *   total_samples in the stream_info block.
+ * - Behavior is undefined when more than one SEEKTABLE block is
+ *   present in a stream.
+ */
+typedef struct {
+	unsigned num_points;
+	FLAC__StreamMetadata_SeekPoint *points;
+} FLAC__StreamMetadata_SeekTable;
+
+
+/** Vorbis comment entry structure used in VORBIS_COMMENT blocks.  (c.f. <A HREF="../format.html#metadata_block_vorbis_comment">format specification</A>)
+ */
+typedef struct {
+	FLAC__uint32 length;
+	FLAC__byte *entry;
+} FLAC__StreamMetadata_VorbisComment_Entry;
+
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN; /**< == 32 (bits) */
+
+
+/** FLAC VORBIS_COMMENT structure.  (c.f. <A HREF="../format.html#metadata_block_vorbis_comment">format specification</A>)
+ */
+typedef struct {
+	FLAC__StreamMetadata_VorbisComment_Entry vendor_string;
+	FLAC__uint32 num_comments;
+	FLAC__StreamMetadata_VorbisComment_Entry *comments;
+} FLAC__StreamMetadata_VorbisComment;
+
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN; /**< == 32 (bits) */
+
+
+/** FLAC CUESHEET track index structure.  (See the
+ * <A HREF="../format.html#cuesheet_track_index">format specification</A> for
+ * the full description of each field.)
+ */
+typedef struct {
+	FLAC__uint64 offset;
+	/**< Offset in samples, relative to the track offset, of the index
+	 * point.
+	 */
+
+	FLAC__byte number;
+	/**< The index point number. */
+} FLAC__StreamMetadata_CueSheet_Index;
+
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN; /**< == 64 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN; /**< == 8 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN; /**< == 3*8 (bits) */
+
+
+/** FLAC CUESHEET track structure.  (See the
+ * <A HREF="../format.html#cuesheet_track">format specification</A> for
+ * the full description of each field.)
+ */
+typedef struct {
+	FLAC__uint64 offset;
+	/**< Track offset in samples, relative to the beginning of the FLAC audio stream. */
+
+	FLAC__byte number;
+	/**< The track number. */
+
+	char isrc[13];
+	/**< Track ISRC.  This is a 12-digit alphanumeric code plus a trailing '\0' */
+
+	unsigned type:1;
+	/**< The track type: 0 for audio, 1 for non-audio. */
+
+	unsigned pre_emphasis:1;
+	/**< The pre-emphasis flag: 0 for no pre-emphasis, 1 for pre-emphasis. */
+
+	FLAC__byte num_indices;
+	/**< The number of track index points. */
+
+	FLAC__StreamMetadata_CueSheet_Index *indices;
+	/**< NULL if num_indices == 0, else pointer to array of index points. */
+
+} FLAC__StreamMetadata_CueSheet_Track;
+
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN; /**< == 64 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN; /**< == 8 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN; /**< == 12*8 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN; /**< == 1 (bit) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN; /**< == 1 (bit) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN; /**< == 6+13*8 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN; /**< == 8 (bits) */
+
+
+/** FLAC CUESHEET structure.  (See the
+ * <A HREF="../format.html#metadata_block_cuesheet">format specification</A>
+ * for the full description of each field.)
+ */
+typedef struct {
+	char media_catalog_number[129];
+	/**< Media catalog number, in ASCII printable characters 0x20-0x7e.  In
+	 * general, the media catalog number may be 0 to 128 bytes long; any
+	 * unused characters should be right-padded with NUL characters.
+	 */
+
+	FLAC__uint64 lead_in;
+	/**< The number of lead-in samples. */
+
+	FLAC__bool is_cd;
+	/**< \c true if CUESHEET corresponds to a Compact Disc, else \c false */
+
+	unsigned num_tracks;
+	/**< The number of tracks. */
+
+	FLAC__StreamMetadata_CueSheet_Track *tracks;
+	/**< NULL if num_tracks == 0, else pointer to array of tracks. */
+
+} FLAC__StreamMetadata_CueSheet;
+
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN; /**< == 128*8 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN; /**< == 64 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN; /**< == 1 (bit) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN; /**< == 7+258*8 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN; /**< == 8 (bits) */
+
+
+/** Structure that is used when a metadata block of unknown type is loaded.
+ *  The contents are opaque.  The structure is used only internally to
+ *  correctly handle unknown metadata.
+ */
+typedef struct {
+	FLAC__byte *data;
+} FLAC__StreamMetadata_Unknown;
+
+
+/** FLAC metadata block structure.  (c.f. <A HREF="../format.html#metadata_block">format specification</A>)
+ */
+typedef struct {
+	FLAC__MetadataType type;
+	/**< The type of the metadata block; used determine which member of the
+	 * \a data union to dereference.  If type >= FLAC__METADATA_TYPE_UNDEFINED
+	 * then \a data.unknown must be used. */
+
+	FLAC__bool is_last;
+	/**< \c true if this metadata block is the last, else \a false */
+
+	unsigned length;
+	/**< Length, in bytes, of the block data as it appears in the stream. */
+
+	union {
+		FLAC__StreamMetadata_StreamInfo stream_info;
+		FLAC__StreamMetadata_Padding padding;
+		FLAC__StreamMetadata_Application application;
+		FLAC__StreamMetadata_SeekTable seek_table;
+		FLAC__StreamMetadata_VorbisComment vorbis_comment;
+		FLAC__StreamMetadata_CueSheet cue_sheet;
+		FLAC__StreamMetadata_Unknown unknown;
+	} data;
+	/**< Polymorphic block data; use the \a type value to determine which
+	 * to use. */
+} FLAC__StreamMetadata;
+
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_IS_LAST_LEN; /**< == 1 (bit) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_TYPE_LEN; /**< == 7 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_LENGTH_LEN; /**< == 24 (bits) */
+
+/** The total stream length of a metadata block header in bytes. */
+#define FLAC__STREAM_METADATA_HEADER_LENGTH (4u)
+
+/*****************************************************************************/
+
+
+/*****************************************************************************
+ *
+ * Utility functions
+ *
+ *****************************************************************************/
+
+/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */
+/** Tests that a sample rate is valid for FLAC.  Since the rules for valid
+ *  sample rates are slightly complex, they are encapsulated in this function.
+ *
+ * \param sample_rate  The sample rate to test for compliance.
+ * \retval FLAC__bool
+ *    \c true if the given sample rate conforms to the specification, else
+ *    \c false.
+ */
+FLAC_API FLAC__bool FLAC__format_sample_rate_is_valid(unsigned sample_rate);
+
+/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */
+/** Check a seek table to see if it conforms to the FLAC specification.
+ *  See the format specification for limits on the contents of the
+ *  seek table.
+ *
+ * \param seek_table  A pointer to a seek table to be checked.
+ * \assert
+ *    \code seek_table != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if seek table is illegal, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__format_seektable_is_legal(const FLAC__StreamMetadata_SeekTable *seek_table);
+
+/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */
+/** Sort a seek table's seek points according to the format specification.
+ *  This includes a "unique-ification" step to remove duplicates, i.e.
+ *  seek points with identical \a sample_number values.  Duplicate seek
+ *  points are converted into placeholder points and sorted to the end of
+ *  the table.
+ *
+ * \param seek_table  A pointer to a seek table to be sorted.
+ * \assert
+ *    \code seek_table != NULL \endcode
+ * \retval unsigned
+ *    The number of duplicate seek points converted into placeholders.
+ */
+FLAC_API unsigned FLAC__format_seektable_sort(FLAC__StreamMetadata_SeekTable *seek_table);
+
+/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */
+/** Check a cue sheet to see if it conforms to the FLAC specification.
+ *  See the format specification for limits on the contents of the
+ *  cue sheet.
+ *
+ * \param cue_sheet  A pointer to an existing cue sheet to be checked.
+ * \param check_cd_da_subset  If \c true, check CUESHEET against more
+ *                   stringent requirements for a CD-DA (audio) disc.
+ * \param violation  Address of a pointer to a string.  If there is a
+ *                   violation, a pointer to a string explanation of the
+ *                   violation will be returned here. \a violation may be
+ *                   \c NULL if you don't need the returned string.  Do not
+ *                   free the returned string; it will always point to static
+ *                   data.
+ * \assert
+ *    \code cue_sheet != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if cue sheet is illegal, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__format_cuesheet_is_legal(const FLAC__StreamMetadata_CueSheet *cue_sheet, FLAC__bool check_cd_da_subset, const char **violation);
+
+/* \} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/FLAC/metadata.h
@@ -1,0 +1,1736 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001,2002,2003,2004  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__METADATA_H
+#define FLAC__METADATA_H
+
+#include "export.h"
+#include "callback.h"
+#include "format.h"
+
+/******************************************************************************
+	(For an example of how all these routines are used, see the source
+	code for the unit tests in src/test_libFLAC/metadata_*.c, or metaflac
+	in src/metaflac/)
+******************************************************************************/
+
+/** \file include/FLAC/metadata.h
+ *
+ *  \brief
+ *  This module provides functions for creating and manipulating FLAC
+ *  metadata blocks in memory, and three progressively more powerful
+ *  interfaces for traversing and editing metadata in FLAC files.
+ *
+ *  See the detailed documentation for each interface in the
+ *  \link flac_metadata metadata \endlink module.
+ */
+
+/** \defgroup flac_metadata FLAC/metadata.h: metadata interfaces
+ *  \ingroup flac
+ *
+ *  \brief
+ *  This module provides functions for creating and manipulating FLAC
+ *  metadata blocks in memory, and three progressively more powerful
+ *  interfaces for traversing and editing metadata in FLAC files.
+ *
+ *  There are three metadata interfaces of increasing complexity:
+ *
+ *  Level 0:
+ *  Read-only access to the STREAMINFO and VORBIS_COMMENT blocks.
+ *
+ *  Level 1:
+ *  Read-write access to all metadata blocks.  This level is write-
+ *  efficient in most cases (more on this below), and uses less memory
+ *  than level 2.
+ *
+ *  Level 2:
+ *  Read-write access to all metadata blocks.  This level is write-
+ *  efficient in all cases, but uses more memory since all metadata for
+ *  the whole file is read into memory and manipulated before writing
+ *  out again.
+ *
+ *  What do we mean by efficient?  Since FLAC metadata appears at the
+ *  beginning of the file, when writing metadata back to a FLAC file
+ *  it is possible to grow or shrink the metadata such that the entire
+ *  file must be rewritten.  However, if the size remains the same during
+ *  changes or PADDING blocks are utilized, only the metadata needs to be
+ *  overwritten, which is much faster.
+ *
+ *  Efficient means the whole file is rewritten at most one time, and only
+ *  when necessary.  Level 1 is not efficient only in the case that you
+ *  cause more than one metadata block to grow or shrink beyond what can
+ *  be accomodated by padding.  In this case you should probably use level
+ *  2, which allows you to edit all the metadata for a file in memory and
+ *  write it out all at once.
+ *
+ *  All levels know how to skip over and not disturb an ID3v2 tag at the
+ *  front of the file.
+ *
+ *  All levels access files via their filenames.  In addition, level 2
+ *  has additional alternative read and write functions that take an I/O
+ *  handle and callbacks, for times when access by filename is not possible.
+ *
+ *  In addition to the three interfaces, this module defines functions for
+ *  creating and manipulating various metadata objects in memory.  As we see
+ *  from the Format module, FLAC metadata blocks in memory are very primitive
+ *  structures for storing information in an efficient way.  Reading
+ *  information from the structures is easy but creating or modifying them
+ *  directly is more complex.  The metadata object routines here facilitate
+ *  this by taking care of the consistency and memory management drudgery.
+ *
+ *  Unless you will be using the level 1 or 2 interfaces to modify existing
+ *  metadata however, you will not probably not need these.
+ *
+ *  From a dependency standpoint, none of the encoders or decoders require
+ *  the metadata module.  This is so that embedded users can strip out the
+ *  metadata module from libFLAC to reduce the size and complexity.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** \defgroup flac_metadata_level0 FLAC/metadata.h: metadata level 0 interface
+ *  \ingroup flac_metadata
+ *
+ *  \brief
+ *  The level 0 interface consists of individual routines to read the
+ *  STREAMINFO and VORBIS_COMMENT blocks, requiring only a filename.
+ *
+ *  It skips any ID3v2 tag at the head of the file.
+ *
+ * \{
+ */
+
+/** Read the STREAMINFO metadata block of the given FLAC file.  This function
+ *  will skip any ID3v2 tag at the head of the file.
+ *
+ * \param filename    The path to the FLAC file to read.
+ * \param streaminfo  A pointer to space for the STREAMINFO block.  Since
+ *                    FLAC__StreamMetadata is a simple structure with no
+ *                    memory allocation involved, you pass the address of
+ *                    an existing structure.  It need not be initialized.
+ * \assert
+ *    \code filename != NULL \endcode
+ *    \code streaminfo != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if a valid STREAMINFO block was read from \a filename.  Returns
+ *    \c false if there was a memory allocation error, a file decoder error,
+ *    or the file contained no STREAMINFO block.  (A memory allocation error
+ *    is possible because this function must set up a file decoder.)
+ */
+FLAC_API FLAC__bool FLAC__metadata_get_streaminfo(const char *filename, FLAC__StreamMetadata *streaminfo);
+
+/** Read the VORBIS_COMMENT metadata block of the given FLAC file.  This
+ *  function will skip any ID3v2 tag at the head of the file.
+ *
+ * \param filename    The path to the FLAC file to read.
+ * \param tags        The address where the returned pointer will be
+ *                    stored.  The \a tags object must be deleted by
+ *                    the caller using FLAC__metadata_object_delete().
+ * \assert
+ *    \code filename != NULL \endcode
+ *    \code streaminfo != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if a valid VORBIS_COMMENT block was read from \a filename,
+ *    and \a *tags will be set to the address of the tag structure.
+ *    Returns \c false if there was a memory allocation error, a file
+ *    decoder error, or the file contained no VORBIS_COMMENT block, and
+ *    \a *tags will be set to \c NULL.
+ */
+FLAC_API FLAC__bool FLAC__metadata_get_tags(const char *filename, FLAC__StreamMetadata **tags);
+
+/* \} */
+
+
+/** \defgroup flac_metadata_level1 FLAC/metadata.h: metadata level 1 interface
+ *  \ingroup flac_metadata
+ *
+ * \brief
+ * The level 1 interface provides read-write access to FLAC file metadata and
+ * operates directly on the FLAC file.
+ *
+ * The general usage of this interface is:
+ *
+ * - Create an iterator using FLAC__metadata_simple_iterator_new()
+ * - Attach it to a file using FLAC__metadata_simple_iterator_init() and check
+ *   the exit code.  Call FLAC__metadata_simple_iterator_is_writable() to
+ *   see if the file is writable, or read-only access is allowed.
+ * - Use FLAC__metadata_simple_iterator_next() and
+ *   FLAC__metadata_simple_iterator_prev() to move around the blocks.
+ *   This is does not read the actual blocks themselves.
+ *   FLAC__metadata_simple_iterator_next() is relatively fast.
+ *   FLAC__metadata_simple_iterator_prev() is slower since it needs to search
+ *   forward from the front of the file.
+ * - Use FLAC__metadata_simple_iterator_get_block_type() or
+ *   FLAC__metadata_simple_iterator_get_block() to access the actual data at
+ *   the current iterator position.  The returned object is yours to modify
+ *   and free.
+ * - Use FLAC__metadata_simple_iterator_set_block() to write a modified block
+ *   back.  You must have write permission to the original file.  Make sure to
+ *   read the whole comment to FLAC__metadata_simple_iterator_set_block()
+ *   below.
+ * - Use FLAC__metadata_simple_iterator_insert_block_after() to add new blocks.
+ *   Use the object creation functions from
+ *   \link flac_metadata_object here \endlink to generate new objects.
+ * - Use FLAC__metadata_simple_iterator_delete_block() to remove the block
+ *   currently referred to by the iterator, or replace it with padding.
+ * - Destroy the iterator with FLAC__metadata_simple_iterator_delete() when
+ *   finished.
+ *
+ * \note
+ * The FLAC file remains open the whole time between
+ * FLAC__metadata_simple_iterator_init() and
+ * FLAC__metadata_simple_iterator_delete(), so make sure you are not altering
+ * the file during this time.
+ *
+ * \note
+ * Do not modify the \a is_last, \a length, or \a type fields of returned
+ * FLAC__StreamMetadata objects.  These are managed automatically.
+ *
+ * \note
+ * If any of the modification functions
+ * (FLAC__metadata_simple_iterator_set_block(),
+ * FLAC__metadata_simple_iterator_delete_block(),
+ * FLAC__metadata_simple_iterator_insert_block_after(), etc.) return \c false,
+ * you should delete the iterator as it may no longer be valid.
+ *
+ * \{
+ */
+
+struct FLAC__Metadata_SimpleIterator;
+/** The opaque structure definition for the level 1 iterator type.
+ *  See the
+ *  \link flac_metadata_level1 metadata level 1 module \endlink
+ *  for a detailed description.
+ */
+typedef struct FLAC__Metadata_SimpleIterator FLAC__Metadata_SimpleIterator;
+
+/** Status type for FLAC__Metadata_SimpleIterator.
+ *
+ *  The iterator's current status can be obtained by calling FLAC__metadata_simple_iterator_status().
+ */
+typedef enum {
+
+	FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK = 0,
+	/**< The iterator is in the normal OK state */
+
+	FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT,
+	/**< The data passed into a function violated the function's usage criteria */
+
+	FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE,
+	/**< The iterator could not open the target file */
+
+	FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE,
+	/**< The iterator could not find the FLAC signature at the start of the file */
+
+	FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE,
+	/**< The iterator tried to write to a file that was not writable */
+
+	FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA,
+	/**< The iterator encountered input that does not conform to the FLAC metadata specification */
+
+	FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR,
+	/**< The iterator encountered an error while reading the FLAC file */
+
+	FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR,
+	/**< The iterator encountered an error while seeking in the FLAC file */
+
+	FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR,
+	/**< The iterator encountered an error while writing the FLAC file */
+
+	FLAC__METADATA_SIMPLE_ITERATOR_STATUS_RENAME_ERROR,
+	/**< The iterator encountered an error renaming the FLAC file */
+
+	FLAC__METADATA_SIMPLE_ITERATOR_STATUS_UNLINK_ERROR,
+	/**< The iterator encountered an error removing the temporary file */
+
+	FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR,
+	/**< Memory allocation failed */
+
+	FLAC__METADATA_SIMPLE_ITERATOR_STATUS_INTERNAL_ERROR
+	/**< The caller violated an assertion or an unexpected error occurred */
+
+} FLAC__Metadata_SimpleIteratorStatus;
+
+/** Maps a FLAC__Metadata_SimpleIteratorStatus to a C string.
+ *
+ *  Using a FLAC__Metadata_SimpleIteratorStatus as the index to this array
+ *  will give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__Metadata_SimpleIteratorStatusString[];
+
+
+/** Create a new iterator instance.
+ *
+ * \retval FLAC__Metadata_SimpleIterator*
+ *    \c NULL if there was an error allocating memory, else the new instance.
+ */
+FLAC_API FLAC__Metadata_SimpleIterator *FLAC__metadata_simple_iterator_new();
+
+/** Free an iterator instance.  Deletes the object pointed to by \a iterator.
+ *
+ * \param iterator  A pointer to an existing iterator.
+ * \assert
+ *    \code iterator != NULL \endcode
+ */
+FLAC_API void FLAC__metadata_simple_iterator_delete(FLAC__Metadata_SimpleIterator *iterator);
+
+/** Get the current status of the iterator.  Call this after a function
+ *  returns \c false to get the reason for the error.  Also resets the status
+ *  to FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK.
+ *
+ * \param iterator  A pointer to an existing iterator.
+ * \assert
+ *    \code iterator != NULL \endcode
+ * \retval FLAC__Metadata_SimpleIteratorStatus
+ *    The current status of the iterator.
+ */
+FLAC_API FLAC__Metadata_SimpleIteratorStatus FLAC__metadata_simple_iterator_status(FLAC__Metadata_SimpleIterator *iterator);
+
+/** Initialize the iterator to point to the first metadata block in the
+ *  given FLAC file.
+ *
+ * \param iterator             A pointer to an existing iterator.
+ * \param filename             The path to the FLAC file.
+ * \param read_only            If \c true, the FLAC file will be opened
+ *                             in read-only mode; if \c false, the FLAC
+ *                             file will be opened for edit even if no
+ *                             edits are performed.
+ * \param preserve_file_stats  If \c true, the owner and modification
+ *                             time will be preserved even if the FLAC
+ *                             file is written to.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \code filename != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if a memory allocation error occurs, the file can't be
+ *    opened, or another error occurs, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_init(FLAC__Metadata_SimpleIterator *iterator, const char *filename, FLAC__bool read_only, FLAC__bool preserve_file_stats);
+
+/** Returns \c true if the FLAC file is writable.  If \c false, calls to
+ *  FLAC__metadata_simple_iterator_set_block() and
+ *  FLAC__metadata_simple_iterator_insert_block_after() will fail.
+ *
+ * \param iterator             A pointer to an existing iterator.
+ * \assert
+ *    \code iterator != NULL \endcode
+ * \retval FLAC__bool
+ *    See above.
+ */
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_is_writable(const FLAC__Metadata_SimpleIterator *iterator);
+
+/** Moves the iterator forward one metadata block, returning \c false if
+ *  already at the end.
+ *
+ * \param iterator  A pointer to an existing initialized iterator.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \a iterator has been successfully initialized with
+ *    FLAC__metadata_simple_iterator_init()
+ * \retval FLAC__bool
+ *    \c false if already at the last metadata block of the chain, else
+ *    \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_next(FLAC__Metadata_SimpleIterator *iterator);
+
+/** Moves the iterator backward one metadata block, returning \c false if
+ *  already at the beginning.
+ *
+ * \param iterator  A pointer to an existing initialized iterator.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \a iterator has been successfully initialized with
+ *    FLAC__metadata_simple_iterator_init()
+ * \retval FLAC__bool
+ *    \c false if already at the first metadata block of the chain, else
+ *    \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_prev(FLAC__Metadata_SimpleIterator *iterator);
+
+/** Get the type of the metadata block at the current position.  This
+ *  avoids reading the actual block data which can save time for large
+ *  blocks.
+ *
+ * \param iterator  A pointer to an existing initialized iterator.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \a iterator has been successfully initialized with
+ *    FLAC__metadata_simple_iterator_init()
+ * \retval FLAC__MetadataType
+ *    The type of the metadata block at the current iterator position.
+ */
+
+FLAC_API FLAC__MetadataType FLAC__metadata_simple_iterator_get_block_type(const FLAC__Metadata_SimpleIterator *iterator);
+
+/** Get the metadata block at the current position.  You can modify the
+ *  block but must use FLAC__metadata_simple_iterator_set_block() to
+ *  write it back to the FLAC file.
+ *
+ *  You must call FLAC__metadata_object_delete() on the returned object
+ *  when you are finished with it.
+ *
+ * \param iterator  A pointer to an existing initialized iterator.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \a iterator has been successfully initialized with
+ *    FLAC__metadata_simple_iterator_init()
+ * \retval FLAC__StreamMetadata*
+ *    The current metadata block.
+ */
+FLAC_API FLAC__StreamMetadata *FLAC__metadata_simple_iterator_get_block(FLAC__Metadata_SimpleIterator *iterator);
+
+/** Write a block back to the FLAC file.  This function tries to be
+ *  as efficient as possible; how the block is actually written is
+ *  shown by the following:
+ *
+ *  Existing block is a STREAMINFO block and the new block is a
+ *  STREAMINFO block: the new block is written in place.  Make sure
+ *  you know what you're doing when changing the values of a
+ *  STREAMINFO block.
+ *
+ *  Existing block is a STREAMINFO block and the new block is a
+ *  not a STREAMINFO block: this is an error since the first block
+ *  must be a STREAMINFO block.  Returns \c false without altering the
+ *  file.
+ *
+ *  Existing block is not a STREAMINFO block and the new block is a
+ *  STREAMINFO block: this is an error since there may be only one
+ *  STREAMINFO block.  Returns \c false without altering the file.
+ *
+ *  Existing block and new block are the same length: the existing
+ *  block will be replaced by the new block, written in place.
+ *
+ *  Existing block is longer than new block: if use_padding is \c true,
+ *  the existing block will be overwritten in place with the new
+ *  block followed by a PADDING block, if possible, to make the total
+ *  size the same as the existing block.  Remember that a padding
+ *  block requires at least four bytes so if the difference in size
+ *  between the new block and existing block is less than that, the
+ *  entire file will have to be rewritten, using the new block's
+ *  exact size.  If use_padding is \c false, the entire file will be
+ *  rewritten, replacing the existing block by the new block.
+ *
+ *  Existing block is shorter than new block: if use_padding is \c true,
+ *  the function will try and expand the new block into the following
+ *  PADDING block, if it exists and doing so won't shrink the PADDING
+ *  block to less than 4 bytes.  If there is no following PADDING
+ *  block, or it will shrink to less than 4 bytes, or use_padding is
+ *  \c false, the entire file is rewritten, replacing the existing block
+ *  with the new block.  Note that in this case any following PADDING
+ *  block is preserved as is.
+ *
+ *  After writing the block, the iterator will remain in the same
+ *  place, i.e. pointing to the new block.
+ *
+ * \param iterator     A pointer to an existing initialized iterator.
+ * \param block        The block to set.
+ * \param use_padding  See above.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \a iterator has been successfully initialized with
+ *    FLAC__metadata_simple_iterator_init()
+ *    \code block != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if successful, else \c false.
+ */
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_set_block(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool use_padding);
+
+/** This is similar to FLAC__metadata_simple_iterator_set_block()
+ *  except that instead of writing over an existing block, it appends
+ *  a block after the existing block.  \a use_padding is again used to
+ *  tell the function to try an expand into following padding in an
+ *  attempt to avoid rewriting the entire file.
+ *
+ *  This function will fail and return \c false if given a STREAMINFO
+ *  block.
+ *
+ *  After writing the block, the iterator will be pointing to the
+ *  new block.
+ *
+ * \param iterator     A pointer to an existing initialized iterator.
+ * \param block        The block to set.
+ * \param use_padding  See above.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \a iterator has been successfully initialized with
+ *    FLAC__metadata_simple_iterator_init()
+ *    \code block != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if successful, else \c false.
+ */
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_insert_block_after(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool use_padding);
+
+/** Deletes the block at the current position.  This will cause the
+ *  entire FLAC file to be rewritten, unless \a use_padding is \c true,
+ *  in which case the block will be replaced by an equal-sized PADDING
+ *  block.  The iterator will be left pointing to the block before the
+ *  one just deleted.
+ *
+ *  You may not delete the STREAMINFO block.
+ *
+ * \param iterator     A pointer to an existing initialized iterator.
+ * \param use_padding  See above.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \a iterator has been successfully initialized with
+ *    FLAC__metadata_simple_iterator_init()
+ * \retval FLAC__bool
+ *    \c true if successful, else \c false.
+ */
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_delete_block(FLAC__Metadata_SimpleIterator *iterator, FLAC__bool use_padding);
+
+/* \} */
+
+
+/** \defgroup flac_metadata_level2 FLAC/metadata.h: metadata level 2 interface
+ *  \ingroup flac_metadata
+ *
+ * \brief
+ * The level 2 interface provides read-write access to FLAC file metadata;
+ * all metadata is read into memory, operated on in memory, and then written
+ * to file, which is more efficient than level 1 when editing multiple blocks.
+ *
+ * The general usage of this interface is:
+ *
+ * - Create a new chain using FLAC__metadata_chain_new().  A chain is a
+ *   linked list of FLAC metadata blocks.
+ * - Read all metadata into the the chain from a FLAC file using
+ *   FLAC__metadata_chain_read() and check the status.
+ * - Optionally, consolidate the padding using
+ *   FLAC__metadata_chain_merge_padding() or
+ *   FLAC__metadata_chain_sort_padding().
+ * - Create a new iterator using FLAC__metadata_iterator_new()
+ * - Initialize the iterator to point to the first element in the chain
+ *   using FLAC__metadata_iterator_init()
+ * - Traverse the chain using FLAC__metadata_iterator_next and
+ *   FLAC__metadata_iterator_prev().
+ * - Get a block for reading or modification using
+ *   FLAC__metadata_iterator_get_block().  The pointer to the object
+ *   inside the chain is returned, so the block is yours to modify.
+ *   Changes will be reflected in the FLAC file when you write the
+ *   chain.  You can also add and delete blocks (see functions below).
+ * - When done, write out the chain using FLAC__metadata_chain_write().
+ *   Make sure to read the whole comment to the function below.
+ * - Delete the chain using FLAC__metadata_chain_delete().
+ *
+ * \note
+ * Even though the FLAC file is not open while the chain is being
+ * manipulated, you must not alter the file externally during
+ * this time.  The chain assumes the FLAC file will not change
+ * between the time of FLAC__metadata_chain_read() and
+ * FLAC__metadata_chain_write().
+ *
+ * \note
+ * Do not modify the is_last, length, or type fields of returned
+ * FLAC__StreamMetadata objects.  These are managed automatically.
+ *
+ * \note
+ * The metadata objects returned by FLAC__metadata_iterator_get_block()
+ * are owned by the chain; do not FLAC__metadata_object_delete() them.
+ * In the same way, blocks passed to FLAC__metadata_iterator_set_block()
+ * become owned by the chain and they will be deleted when the chain is
+ * deleted.
+ *
+ * \{
+ */
+
+struct FLAC__Metadata_Chain;
+/** The opaque structure definition for the level 2 chain type.
+ */
+typedef struct FLAC__Metadata_Chain FLAC__Metadata_Chain;
+
+struct FLAC__Metadata_Iterator;
+/** The opaque structure definition for the level 2 iterator type.
+ */
+typedef struct FLAC__Metadata_Iterator FLAC__Metadata_Iterator;
+
+typedef enum {
+	FLAC__METADATA_CHAIN_STATUS_OK = 0,
+	/**< The chain is in the normal OK state */
+
+	FLAC__METADATA_CHAIN_STATUS_ILLEGAL_INPUT,
+	/**< The data passed into a function violated the function's usage criteria */
+
+	FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE,
+	/**< The chain could not open the target file */
+
+	FLAC__METADATA_CHAIN_STATUS_NOT_A_FLAC_FILE,
+	/**< The chain could not find the FLAC signature at the start of the file */
+
+	FLAC__METADATA_CHAIN_STATUS_NOT_WRITABLE,
+	/**< The chain tried to write to a file that was not writable */
+
+	FLAC__METADATA_CHAIN_STATUS_BAD_METADATA,
+	/**< The chain encountered input that does not conform to the FLAC metadata specification */
+
+	FLAC__METADATA_CHAIN_STATUS_READ_ERROR,
+	/**< The chain encountered an error while reading the FLAC file */
+
+	FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR,
+	/**< The chain encountered an error while seeking in the FLAC file */
+
+	FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR,
+	/**< The chain encountered an error while writing the FLAC file */
+
+	FLAC__METADATA_CHAIN_STATUS_RENAME_ERROR,
+	/**< The chain encountered an error renaming the FLAC file */
+
+	FLAC__METADATA_CHAIN_STATUS_UNLINK_ERROR,
+	/**< The chain encountered an error removing the temporary file */
+
+	FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR,
+	/**< Memory allocation failed */
+
+	FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR,
+	/**< The caller violated an assertion or an unexpected error occurred */
+
+	FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS,
+	/**< One or more of the required callbacks was NULL */
+
+	FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH,
+	/**< FLAC__metadata_chain_write() was called on a chain read by
+	 *   FLAC__metadata_chain_read_with_callbacks(), or
+	 *   FLAC__metadata_chain_write_with_callbacks() or
+	 *   FLAC__metadata_chain_write_with_callbacks_and_tempfile() was
+	 *   called on a chain read by FLAC__metadata_chain_read().  Matching
+	 *   read/write methods must always be used. */
+
+	FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL
+	/**< FLAC__metadata_chain_write_with_callbacks() was called when the
+	 *   chain write requires a tempfile; use
+	 *   FLAC__metadata_chain_write_with_callbacks_and_tempfile() instead.
+	 *   Or, FLAC__metadata_chain_write_with_callbacks_and_tempfile() was
+	 *   called when the chain write does not require a tempfile; use
+	 *   FLAC__metadata_chain_write_with_callbacks() instead.
+	 *   Always check FLAC__metadata_chain_check_if_tempfile_needed()
+	 *   before writing via callbacks. */
+
+} FLAC__Metadata_ChainStatus;
+
+/** Maps a FLAC__Metadata_ChainStatus to a C string.
+ *
+ *  Using a FLAC__Metadata_ChainStatus as the index to this array
+ *  will give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__Metadata_ChainStatusString[];
+
+/*********** FLAC__Metadata_Chain ***********/
+
+/** Create a new chain instance.
+ *
+ * \retval FLAC__Metadata_Chain*
+ *    \c NULL if there was an error allocating memory, else the new instance.
+ */
+FLAC_API FLAC__Metadata_Chain *FLAC__metadata_chain_new();
+
+/** Free a chain instance.  Deletes the object pointed to by \a chain.
+ *
+ * \param chain  A pointer to an existing chain.
+ * \assert
+ *    \code chain != NULL \endcode
+ */
+FLAC_API void FLAC__metadata_chain_delete(FLAC__Metadata_Chain *chain);
+
+/** Get the current status of the chain.  Call this after a function
+ *  returns \c false to get the reason for the error.  Also resets the
+ *  status to FLAC__METADATA_CHAIN_STATUS_OK.
+ *
+ * \param chain    A pointer to an existing chain.
+ * \assert
+ *    \code chain != NULL \endcode
+ * \retval FLAC__Metadata_ChainStatus
+ *    The current status of the chain.
+ */
+FLAC_API FLAC__Metadata_ChainStatus FLAC__metadata_chain_status(FLAC__Metadata_Chain *chain);
+
+/** Read all metadata from a FLAC file into the chain.
+ *
+ * \param chain    A pointer to an existing chain.
+ * \param filename The path to the FLAC file to read.
+ * \assert
+ *    \code chain != NULL \endcode
+ *    \code filename != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if a valid list of metadata blocks was read from
+ *    \a filename, else \c false.  On failure, check the status with
+ *    FLAC__metadata_chain_status().
+ */
+FLAC_API FLAC__bool FLAC__metadata_chain_read(FLAC__Metadata_Chain *chain, const char *filename);
+
+/** Read all metadata from a FLAC stream into the chain via I/O callbacks.
+ *
+ *  The \a handle need only be open for reading, but must be seekable.
+ *  The equivalent minimum stdio fopen() file mode is \c "r" (or \c "rb"
+ *  for Windows).
+ *
+ * \param chain    A pointer to an existing chain.
+ * \param handle   The I/O handle of the FLAC stream to read.  The
+ *                 handle will NOT be closed after the metadata is read;
+ *                 that is the duty of the caller.
+ * \param callbacks
+ *                 A set of callbacks to use for I/O.  The mandatory
+ *                 callbacks are \a read, \a seek, and \a tell.
+ * \assert
+ *    \code chain != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if a valid list of metadata blocks was read from
+ *    \a handle, else \c false.  On failure, check the status with
+ *    FLAC__metadata_chain_status().
+ */
+FLAC_API FLAC__bool FLAC__metadata_chain_read_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks);
+
+/** Checks if writing the given chain would require the use of a
+ *  temporary file, or if it could be written in place.
+ *
+ *  Under certain conditions, padding can be utilized so that writing
+ *  edited metadata back to the FLAC file does not require rewriting the
+ *  entire file.  If rewriting is required, then a temporary workfile is
+ *  required.  When writing metadata using callbacks, you must check
+ *  this function to know whether to call
+ *  FLAC__metadata_chain_write_with_callbacks() or
+ *  FLAC__metadata_chain_write_with_callbacks_and_tempfile().  When
+ *  writing with FLAC__metadata_chain_write(), the temporary file is
+ *  handled internally.
+ *
+ * \param chain    A pointer to an existing chain.
+ * \param use_padding
+ *                 Whether or not padding will be allowed to be used
+ *                 during the write.  The value of \a use_padding given
+ *                 here must match the value later passed to
+ *                 FLAC__metadata_chain_write_with_callbacks() or
+ *                 FLAC__metadata_chain_write_with_callbacks_with_tempfile().
+ * \assert
+ *    \code chain != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if writing the current chain would require a tempfile, or
+ *    \c false if metadata can be written in place.
+ */
+FLAC_API FLAC__bool FLAC__metadata_chain_check_if_tempfile_needed(FLAC__Metadata_Chain *chain, FLAC__bool use_padding);
+
+/** Write all metadata out to the FLAC file.  This function tries to be as
+ *  efficient as possible; how the metadata is actually written is shown by
+ *  the following:
+ *
+ *  If the current chain is the same size as the existing metadata, the new
+ *  data is written in place.
+ *
+ *  If the current chain is longer than the existing metadata, and
+ *  \a use_padding is \c true, and the last block is a PADDING block of
+ *  sufficient length, the function will truncate the final padding block
+ *  so that the overall size of the metadata is the same as the existing
+ *  metadata, and then just rewrite the metadata.  Otherwise, if not all of
+ *  the above conditions are met, the entire FLAC file must be rewritten.
+ *  If you want to use padding this way it is a good idea to call
+ *  FLAC__metadata_chain_sort_padding() first so that you have the maximum
+ *  amount of padding to work with, unless you need to preserve ordering
+ *  of the PADDING blocks for some reason.
+ *
+ *  If the current chain is shorter than the existing metadata, and
+ *  \a use_padding is \c true, and the final block is a PADDING block, the padding
+ *  is extended to make the overall size the same as the existing data.  If
+ *  \a use_padding is \c true and the last block is not a PADDING block, a new
+ *  PADDING block is added to the end of the new data to make it the same
+ *  size as the existing data (if possible, see the note to
+ *  FLAC__metadata_simple_iterator_set_block() about the four byte limit)
+ *  and the new data is written in place.  If none of the above apply or
+ *  \a use_padding is \c false, the entire FLAC file is rewritten.
+ *
+ *  If \a preserve_file_stats is \c true, the owner and modification time will
+ *  be preserved even if the FLAC file is written.
+ *
+ *  For this write function to be used, the chain must have been read with
+ *  FLAC__metadata_chain_read(), not FLAC__metadata_chain_read_with_callbacks().
+ *
+ * \param chain               A pointer to an existing chain.
+ * \param use_padding         See above.
+ * \param preserve_file_stats See above.
+ * \assert
+ *    \code chain != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if the write succeeded, else \c false.  On failure,
+ *    check the status with FLAC__metadata_chain_status().
+ */
+FLAC_API FLAC__bool FLAC__metadata_chain_write(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__bool preserve_file_stats);
+
+/** Write all metadata out to a FLAC stream via callbacks.
+ *
+ *  (See FLAC__metadata_chain_write() for the details on how padding is
+ *  used to write metadata in place if possible.)
+ *
+ *  The \a handle must be open for updating and be seekable.  The
+ *  equivalent minimum stdio fopen() file mode is \c "r+" (or \c "r+b"
+ *  for Windows).
+ *
+ *  For this write function to be used, the chain must have been read with
+ *  FLAC__metadata_chain_read_with_callbacks(), not FLAC__metadata_chain_read().
+ *  Also, FLAC__metadata_chain_check_if_tempfile_needed() must have returned
+ *  \c false.
+ *
+ * \param chain        A pointer to an existing chain.
+ * \param use_padding  See FLAC__metadata_chain_write()
+ * \param handle       The I/O handle of the FLAC stream to write.  The
+ *                     handle will NOT be closed after the metadata is
+ *                     written; that is the duty of the caller.
+ * \param callbacks    A set of callbacks to use for I/O.  The mandatory
+ *                     callbacks are \a write and \a seek.
+ * \assert
+ *    \code chain != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if the write succeeded, else \c false.  On failure,
+ *    check the status with FLAC__metadata_chain_status().
+ */
+FLAC_API FLAC__bool FLAC__metadata_chain_write_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks);
+
+/** Write all metadata out to a FLAC stream via callbacks.
+ *
+ *  (See FLAC__metadata_chain_write() for the details on how padding is
+ *  used to write metadata in place if possible.)
+ *
+ *  This version of the write-with-callbacks function must be used when
+ *  FLAC__metadata_chain_check_if_tempfile_needed() returns true.  In
+ *  this function, you must supply an I/O handle corresponding to the
+ *  FLAC file to edit, and a temporary handle to which the new FLAC
+ *  file will be written.  It is the caller's job to move this temporary
+ *  FLAC file on top of the original FLAC file to complete the metadata
+ *  edit.
+ *
+ *  The \a handle must be open for reading and be seekable.  The
+ *  equivalent minimum stdio fopen() file mode is \c "r" (or \c "rb"
+ *  for Windows).
+ *
+ *  The \a temp_handle must be open for writing.  The
+ *  equivalent minimum stdio fopen() file mode is \c "w" (or \c "wb"
+ *  for Windows).  It should be an empty stream, or at least positioned
+ *  at the start-of-file (in which case it is the caller's duty to
+ *  truncate it on return).
+ *
+ *  For this write function to be used, the chain must have been read with
+ *  FLAC__metadata_chain_read_with_callbacks(), not FLAC__metadata_chain_read().
+ *  Also, FLAC__metadata_chain_check_if_tempfile_needed() must have returned
+ *  \c true.
+ *
+ * \param chain        A pointer to an existing chain.
+ * \param use_padding  See FLAC__metadata_chain_write()
+ * \param handle       The I/O handle of the original FLAC stream to read.
+ *                     The handle will NOT be closed after the metadata is
+ *                     written; that is the duty of the caller.
+ * \param callbacks    A set of callbacks to use for I/O on \a handle.
+ *                     The mandatory callbacks are \a read, \a seek, and
+ *                     \a eof.
+ * \param temp_handle  The I/O handle of the FLAC stream to write.  The
+ *                     handle will NOT be closed after the metadata is
+ *                     written; that is the duty of the caller.
+ * \param temp_callbacks
+ *                     A set of callbacks to use for I/O on temp_handle.
+ *                     The only mandatory callback is \a write.
+ * \assert
+ *    \code chain != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if the write succeeded, else \c false.  On failure,
+ *    check the status with FLAC__metadata_chain_status().
+ */
+FLAC_API FLAC__bool FLAC__metadata_chain_write_with_callbacks_and_tempfile(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks, FLAC__IOHandle temp_handle, FLAC__IOCallbacks temp_callbacks);
+
+/** Merge adjacent PADDING blocks into a single block.
+ *
+ * \note This function does not write to the FLAC file, it only
+ * modifies the chain.
+ *
+ * \warning Any iterator on the current chain will become invalid after this
+ * call.  You should delete the iterator and get a new one.
+ *
+ * \param chain               A pointer to an existing chain.
+ * \assert
+ *    \code chain != NULL \endcode
+ */
+FLAC_API void FLAC__metadata_chain_merge_padding(FLAC__Metadata_Chain *chain);
+
+/** This function will move all PADDING blocks to the end on the metadata,
+ *  then merge them into a single block.
+ *
+ * \note This function does not write to the FLAC file, it only
+ * modifies the chain.
+ *
+ * \warning Any iterator on the current chain will become invalid after this
+ * call.  You should delete the iterator and get a new one.
+ *
+ * \param chain  A pointer to an existing chain.
+ * \assert
+ *    \code chain != NULL \endcode
+ */
+FLAC_API void FLAC__metadata_chain_sort_padding(FLAC__Metadata_Chain *chain);
+
+
+/*********** FLAC__Metadata_Iterator ***********/
+
+/** Create a new iterator instance.
+ *
+ * \retval FLAC__Metadata_Iterator*
+ *    \c NULL if there was an error allocating memory, else the new instance.
+ */
+FLAC_API FLAC__Metadata_Iterator *FLAC__metadata_iterator_new();
+
+/** Free an iterator instance.  Deletes the object pointed to by \a iterator.
+ *
+ * \param iterator  A pointer to an existing iterator.
+ * \assert
+ *    \code iterator != NULL \endcode
+ */
+FLAC_API void FLAC__metadata_iterator_delete(FLAC__Metadata_Iterator *iterator);
+
+/** Initialize the iterator to point to the first metadata block in the
+ *  given chain.
+ *
+ * \param iterator  A pointer to an existing iterator.
+ * \param chain     A pointer to an existing and initialized (read) chain.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \code chain != NULL \endcode
+ */
+FLAC_API void FLAC__metadata_iterator_init(FLAC__Metadata_Iterator *iterator, FLAC__Metadata_Chain *chain);
+
+/** Moves the iterator forward one metadata block, returning \c false if
+ *  already at the end.
+ *
+ * \param iterator  A pointer to an existing initialized iterator.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \a iterator has been successfully initialized with
+ *    FLAC__metadata_iterator_init()
+ * \retval FLAC__bool
+ *    \c false if already at the last metadata block of the chain, else
+ *    \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_iterator_next(FLAC__Metadata_Iterator *iterator);
+
+/** Moves the iterator backward one metadata block, returning \c false if
+ *  already at the beginning.
+ *
+ * \param iterator  A pointer to an existing initialized iterator.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \a iterator has been successfully initialized with
+ *    FLAC__metadata_iterator_init()
+ * \retval FLAC__bool
+ *    \c false if already at the first metadata block of the chain, else
+ *    \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_iterator_prev(FLAC__Metadata_Iterator *iterator);
+
+/** Get the type of the metadata block at the current position.
+ *
+ * \param iterator  A pointer to an existing initialized iterator.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \a iterator has been successfully initialized with
+ *    FLAC__metadata_iterator_init()
+ * \retval FLAC__MetadataType
+ *    The type of the metadata block at the current iterator position.
+ */
+FLAC_API FLAC__MetadataType FLAC__metadata_iterator_get_block_type(const FLAC__Metadata_Iterator *iterator);
+
+/** Get the metadata block at the current position.  You can modify
+ *  the block in place but must write the chain before the changes
+ *  are reflected to the FLAC file.  You do not need to call
+ *  FLAC__metadata_iterator_set_block() to reflect the changes;
+ *  the pointer returned by FLAC__metadata_iterator_get_block()
+ *  points directly into the chain.
+ *
+ * \warning
+ * Do not call FLAC__metadata_object_delete() on the returned object;
+ * to delete a block use FLAC__metadata_iterator_delete_block().
+ *
+ * \param iterator  A pointer to an existing initialized iterator.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \a iterator has been successfully initialized with
+ *    FLAC__metadata_iterator_init()
+ * \retval FLAC__StreamMetadata*
+ *    The current metadata block.
+ */
+FLAC_API FLAC__StreamMetadata *FLAC__metadata_iterator_get_block(FLAC__Metadata_Iterator *iterator);
+
+/** Set the metadata block at the current position, replacing the existing
+ *  block.  The new block passed in becomes owned by the chain and it will be
+ *  deleted when the chain is deleted.
+ *
+ * \param iterator  A pointer to an existing initialized iterator.
+ * \param block     A pointer to a metadata block.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \a iterator has been successfully initialized with
+ *    FLAC__metadata_iterator_init()
+ *    \code block != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the conditions in the above description are not met, or
+ *    a memory allocation error occurs, otherwise \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_iterator_set_block(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block);
+
+/** Removes the current block from the chain.  If \a replace_with_padding is
+ *  \c true, the block will instead be replaced with a padding block of equal
+ *  size.  You can not delete the STREAMINFO block.  The iterator will be
+ *  left pointing to the block before the one just "deleted", even if
+ *  \a replace_with_padding is \c true.
+ *
+ * \param iterator              A pointer to an existing initialized iterator.
+ * \param replace_with_padding  See above.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \a iterator has been successfully initialized with
+ *    FLAC__metadata_iterator_init()
+ * \retval FLAC__bool
+ *    \c false if the conditions in the above description are not met,
+ *    otherwise \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_iterator_delete_block(FLAC__Metadata_Iterator *iterator, FLAC__bool replace_with_padding);
+
+/** Insert a new block before the current block.  You cannot insert a block
+ *  before the first STREAMINFO block.  You cannot insert a STREAMINFO block
+ *  as there can be only one, the one that already exists at the head when you
+ *  read in a chain.  The chain takes ownership of the new block and it will be
+ *  deleted when the chain is deleted.  The iterator will be left pointing to
+ *  the new block.
+ *
+ * \param iterator  A pointer to an existing initialized iterator.
+ * \param block     A pointer to a metadata block to insert.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \a iterator has been successfully initialized with
+ *    FLAC__metadata_iterator_init()
+ * \retval FLAC__bool
+ *    \c false if the conditions in the above description are not met, or
+ *    a memory allocation error occurs, otherwise \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_iterator_insert_block_before(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block);
+
+/** Insert a new block after the current block.  You cannot insert a STREAMINFO
+ *  block as there can be only one, the one that already exists at the head when
+ *  you read in a chain.  The chain takes ownership of the new block and it will
+ *  be deleted when the chain is deleted.  The iterator will be left pointing to
+ *  the new block.
+ *
+ * \param iterator  A pointer to an existing initialized iterator.
+ * \param block     A pointer to a metadata block to insert.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \a iterator has been successfully initialized with
+ *    FLAC__metadata_iterator_init()
+ * \retval FLAC__bool
+ *    \c false if the conditions in the above description are not met, or
+ *    a memory allocation error occurs, otherwise \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_iterator_insert_block_after(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block);
+
+/* \} */
+
+
+/** \defgroup flac_metadata_object FLAC/metadata.h: metadata object methods
+ *  \ingroup flac_metadata
+ *
+ * \brief
+ * This module contains methods for manipulating FLAC metadata objects.
+ *
+ * Since many are variable length we have to be careful about the memory
+ * management.  We decree that all pointers to data in the object are
+ * owned by the object and memory-managed by the object.
+ *
+ * Use the FLAC__metadata_object_new() and FLAC__metadata_object_delete()
+ * functions to create all instances.  When using the
+ * FLAC__metadata_object_set_*() functions to set pointers to data, set
+ * \a copy to \c true to have the function make it's own copy of the data, or
+ * to \c false to give the object ownership of your data.  In the latter case
+ * your pointer must be freeable by free() and will be free()d when the object
+ * is FLAC__metadata_object_delete()d.  It is legal to pass a null pointer as
+ * the data pointer to a FLAC__metadata_object_set_*() function as long as
+ * the length argument is 0 and the \a copy argument is \c false.
+ *
+ * The FLAC__metadata_object_new() and FLAC__metadata_object_clone() function
+ * will return \c NULL in the case of a memory allocation error, otherwise a new
+ * object.  The FLAC__metadata_object_set_*() functions return \c false in the
+ * case of a memory allocation error.
+ *
+ * We don't have the convenience of C++ here, so note that the library relies
+ * on you to keep the types straight.  In other words, if you pass, for
+ * example, a FLAC__StreamMetadata* that represents a STREAMINFO block to
+ * FLAC__metadata_object_application_set_data(), you will get an assertion
+ * failure.
+ *
+ * There is no need to recalculate the length field on metadata blocks you
+ * have modified.  They will be calculated automatically before they  are
+ * written back to a file.
+ *
+ * \{
+ */
+
+
+/** Create a new metadata object instance of the given type.
+ *
+ *  The object will be "empty"; i.e. values and data pointers will be \c 0,
+ *  with the exception of FLAC__METADATA_TYPE_VORBIS_COMMENT, which will have
+ *  the vendor string set (but zero comments).
+ *
+ *  Do not pass in a value greater than or equal to
+ *  \a FLAC__METADATA_TYPE_UNDEFINED unless you really know what you're
+ *  doing.
+ *
+ * \param type  Type of object to create
+ * \retval FLAC__StreamMetadata*
+ *    \c NULL if there was an error allocating memory or the type code is
+ *    greater than FLAC__MAX_METADATA_TYPE_CODE, else the new instance.
+ */
+FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_new(FLAC__MetadataType type);
+
+/** Create a copy of an existing metadata object.
+ *
+ *  The copy is a "deep" copy, i.e. dynamically allocated data within the
+ *  object is also copied.  The caller takes ownership of the new block and
+ *  is responsible for freeing it with FLAC__metadata_object_delete().
+ *
+ * \param object  Pointer to object to copy.
+ * \assert
+ *    \code object != NULL \endcode
+ * \retval FLAC__StreamMetadata*
+ *    \c NULL if there was an error allocating memory, else the new instance.
+ */
+FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_clone(const FLAC__StreamMetadata *object);
+
+/** Free a metadata object.  Deletes the object pointed to by \a object.
+ *
+ *  The delete is a "deep" delete, i.e. dynamically allocated data within the
+ *  object is also deleted.
+ *
+ * \param object  A pointer to an existing object.
+ * \assert
+ *    \code object != NULL \endcode
+ */
+FLAC_API void FLAC__metadata_object_delete(FLAC__StreamMetadata *object);
+
+/** Compares two metadata objects.
+ *
+ *  The compare is "deep", i.e. dynamically allocated data within the
+ *  object is also compared.
+ *
+ * \param block1  A pointer to an existing object.
+ * \param block2  A pointer to an existing object.
+ * \assert
+ *    \code block1 != NULL \endcode
+ *    \code block2 != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if objects are identical, else \c false.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_is_equal(const FLAC__StreamMetadata *block1, const FLAC__StreamMetadata *block2);
+
+/** Sets the application data of an APPLICATION block.
+ *
+ *  If \a copy is \c true, a copy of the data is stored; otherwise, the object
+ *  takes ownership of the pointer.  Returns \c false if \a copy == \c true
+ *  and malloc fails.
+ *
+ * \param object  A pointer to an existing APPLICATION object.
+ * \param data    A pointer to the data to set.
+ * \param length  The length of \a data in bytes.
+ * \param copy    See above.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_APPLICATION \endcode
+ *    \code (data != NULL && length > 0) ||
+ * (data == NULL && length == 0 && copy == false) \endcode
+ * \retval FLAC__bool
+ *    \c false if \a copy is \c true and malloc fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_application_set_data(FLAC__StreamMetadata *object, FLAC__byte *data, unsigned length, FLAC__bool copy);
+
+/** Resize the seekpoint array.
+ *
+ *  If the size shrinks, elements will truncated; if it grows, new placeholder
+ *  points will be added to the end.
+ *
+ * \param object          A pointer to an existing SEEKTABLE object.
+ * \param new_num_points  The desired length of the array; may be \c 0.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ *    \code (object->data.seek_table.points == NULL && object->data.seek_table.num_points == 0) ||
+ * (object->data.seek_table.points != NULL && object->data.seek_table.num_points > 0) \endcode
+ * \retval FLAC__bool
+ *    \c false if memory allocation error, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_resize_points(FLAC__StreamMetadata *object, unsigned new_num_points);
+
+/** Set a seekpoint in a seektable.
+ *
+ * \param object     A pointer to an existing SEEKTABLE object.
+ * \param point_num  Index into seekpoint array to set.
+ * \param point      The point to set.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ *    \code object->data.seek_table.num_points > point_num \endcode
+ */
+FLAC_API void FLAC__metadata_object_seektable_set_point(FLAC__StreamMetadata *object, unsigned point_num, FLAC__StreamMetadata_SeekPoint point);
+
+/** Insert a seekpoint into a seektable.
+ *
+ * \param object     A pointer to an existing SEEKTABLE object.
+ * \param point_num  Index into seekpoint array to set.
+ * \param point      The point to set.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ *    \code object->data.seek_table.num_points >= point_num \endcode
+ * \retval FLAC__bool
+ *    \c false if memory allocation error, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_insert_point(FLAC__StreamMetadata *object, unsigned point_num, FLAC__StreamMetadata_SeekPoint point);
+
+/** Delete a seekpoint from a seektable.
+ *
+ * \param object     A pointer to an existing SEEKTABLE object.
+ * \param point_num  Index into seekpoint array to set.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ *    \code object->data.seek_table.num_points > point_num \endcode
+ * \retval FLAC__bool
+ *    \c false if memory allocation error, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_delete_point(FLAC__StreamMetadata *object, unsigned point_num);
+
+/** Check a seektable to see if it conforms to the FLAC specification.
+ *  See the format specification for limits on the contents of the
+ *  seektable.
+ *
+ * \param object  A pointer to an existing SEEKTABLE object.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ * \retval FLAC__bool
+ *    \c false if seek table is illegal, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_is_legal(const FLAC__StreamMetadata *object);
+
+/** Append a number of placeholder points to the end of a seek table.
+ *
+ * \note
+ * As with the other ..._seektable_template_... functions, you should
+ * call FLAC__metadata_object_seektable_template_sort() when finished
+ * to make the seek table legal.
+ *
+ * \param object  A pointer to an existing SEEKTABLE object.
+ * \param num     The number of placeholder points to append.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ * \retval FLAC__bool
+ *    \c false if memory allocation fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_placeholders(FLAC__StreamMetadata *object, unsigned num);
+
+/** Append a specific seek point template to the end of a seek table.
+ *
+ * \note
+ * As with the other ..._seektable_template_... functions, you should
+ * call FLAC__metadata_object_seektable_template_sort() when finished
+ * to make the seek table legal.
+ *
+ * \param object  A pointer to an existing SEEKTABLE object.
+ * \param sample_number  The sample number of the seek point template.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ * \retval FLAC__bool
+ *    \c false if memory allocation fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_point(FLAC__StreamMetadata *object, FLAC__uint64 sample_number);
+
+/** Append specific seek point templates to the end of a seek table.
+ *
+ * \note
+ * As with the other ..._seektable_template_... functions, you should
+ * call FLAC__metadata_object_seektable_template_sort() when finished
+ * to make the seek table legal.
+ *
+ * \param object  A pointer to an existing SEEKTABLE object.
+ * \param sample_numbers  An array of sample numbers for the seek points.
+ * \param num     The number of seek point templates to append.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ * \retval FLAC__bool
+ *    \c false if memory allocation fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_points(FLAC__StreamMetadata *object, FLAC__uint64 sample_numbers[], unsigned num);
+
+/** Append a set of evenly-spaced seek point templates to the end of a
+ *  seek table.
+ *
+ * \note
+ * As with the other ..._seektable_template_... functions, you should
+ * call FLAC__metadata_object_seektable_template_sort() when finished
+ * to make the seek table legal.
+ *
+ * \param object  A pointer to an existing SEEKTABLE object.
+ * \param num     The number of placeholder points to append.
+ * \param total_samples  The total number of samples to be encoded;
+ *                       the seekpoints will be spaced approximately
+ *                       \a total_samples / \a num samples apart.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ * \retval FLAC__bool
+ *    \c false if memory allocation fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_points(FLAC__StreamMetadata *object, unsigned num, FLAC__uint64 total_samples);
+
+/** Sort a seek table's seek points according to the format specification,
+ *  removing duplicates.
+ *
+ * \param object   A pointer to a seek table to be sorted.
+ * \param compact  If \c false, behaves like FLAC__format_seektable_sort().
+ *                 If \c true, duplicates are deleted and the seek table is
+ *                 shrunk appropriately; the number of placeholder points
+ *                 present in the seek table will be the same after the call
+ *                 as before.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ * \retval FLAC__bool
+ *    \c false if realloc fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_sort(FLAC__StreamMetadata *object, FLAC__bool compact);
+
+/** Sets the vendor string in a VORBIS_COMMENT block.
+ *
+ *  If \a copy is \c true, a copy of the entry is stored; otherwise, the object
+ *  takes ownership of the \c entry->entry pointer.  Returns \c false if
+ *  \a copy == \c true and malloc fails.
+ *
+ * \param object  A pointer to an existing VORBIS_COMMENT object.
+ * \param entry   The entry to set the vendor string to.
+ * \param copy    See above.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
+ *    \code (entry->entry != NULL && entry->length > 0) ||
+ * (entry->entry == NULL && entry->length == 0) \endcode
+ * \retval FLAC__bool
+ *    \c false if \a copy is \c true and malloc fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_vendor_string(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy);
+
+/** Resize the comment array.
+ *
+ *  If the size shrinks, elements will truncated; if it grows, new empty
+ *  fields will be added to the end.
+ *
+ * \param object            A pointer to an existing VORBIS_COMMENT object.
+ * \param new_num_comments  The desired length of the array; may be \c 0.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
+ *    \code (object->data.vorbis_comment.comments == NULL && object->data.vorbis_comment.num_comments == 0) ||
+ * (object->data.vorbis_comment.comments != NULL && object->data.vorbis_comment.num_comments > 0) \endcode
+ * \retval FLAC__bool
+ *    \c false if memory allocation error, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_resize_comments(FLAC__StreamMetadata *object, unsigned new_num_comments);
+
+/** Sets a comment in a VORBIS_COMMENT block.
+ *
+ *  If \a copy is \c true, a copy of the entry is stored; otherwise, the object
+ *  takes ownership of the \c entry->entry pointer.  Returns \c false if
+ *  \a copy == \c true and malloc fails.
+ *
+ * \param object       A pointer to an existing VORBIS_COMMENT object.
+ * \param comment_num  Index into comment array to set.
+ * \param entry        The entry to set the comment to.
+ * \param copy         See above.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
+ *    \code comment_num < object->data.vorbis_comment.num_comments \endcode
+ *    \code (entry->entry != NULL && entry->length > 0) ||
+ * (entry->entry == NULL && entry->length == 0) \endcode
+ * \retval FLAC__bool
+ *    \c false if \a copy is \c true and malloc fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_comment(FLAC__StreamMetadata *object, unsigned comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy);
+
+/** Insert a comment in a VORBIS_COMMENT block at the given index.
+ *
+ *  If \a copy is \c true, a copy of the entry is stored; otherwise, the object
+ *  takes ownership of the \c entry->entry pointer.  Returns \c false if
+ *  \a copy == \c true and malloc fails.
+ *
+ * \param object       A pointer to an existing VORBIS_COMMENT object.
+ * \param comment_num  The index at which to insert the comment.  The comments
+ *                     at and after \a comment_num move right one position.
+ *                     To append a comment to the end, set \a comment_num to
+ *                     \c object->data.vorbis_comment.num_comments .
+ * \param entry        The comment to insert.
+ * \param copy         See above.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
+ *    \code object->data.vorbis_comment.num_comments >= comment_num \endcode
+ *    \code (entry->entry != NULL && entry->length > 0) ||
+ * (entry->entry == NULL && entry->length == 0 && copy == false) \endcode
+ * \retval FLAC__bool
+ *    \c false if \a copy is \c true and malloc fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_insert_comment(FLAC__StreamMetadata *object, unsigned comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy);
+
+/** Delete a comment in a VORBIS_COMMENT block at the given index.
+ *
+ * \param object       A pointer to an existing VORBIS_COMMENT object.
+ * \param comment_num  The index of the comment to delete.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
+ *    \code object->data.vorbis_comment.num_comments > comment_num \endcode
+ *    \code (entry->entry != NULL && entry->length > 0) ||
+ * (entry->entry == NULL && entry->length == 0 && copy == false) \endcode
+ * \retval FLAC__bool
+ *    \c false if realloc fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_delete_comment(FLAC__StreamMetadata *object, unsigned comment_num);
+
+/*@@@@ add to unit tests */
+/** Check if the given Vorbis comment entry's field name matches the given
+ *  field name.
+ *
+ * \param entry              A pointer to an existing Vorbis comment entry.
+ * \param field_name         The field name to check.
+ * \param field_name_length  The length of \a field_name, not including the
+ *                           terminating \c NULL.
+ * \assert
+ *    \code entry != NULL \endcode
+ *    \code (entry->entry != NULL && entry->length > 0) \endcode
+ * \retval FLAC__bool
+ *    \c true if the field names match, else \c false
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_matches(const FLAC__StreamMetadata_VorbisComment_Entry *entry, const char *field_name, unsigned field_name_length);
+
+/*@@@@ add to unit tests */
+/** Find a Vorbis comment with the given field name.
+ *
+ *  The search begins at entry number \a offset; use an offset of 0 to
+ *  search from the beginning of the comment array.
+ *
+ * \param object      A pointer to an existing VORBIS_COMMENT object.
+ * \param offset      The offset into the comment array from where to start
+ *                    the search.
+ * \param field_name  The field name of the comment to find.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
+ * \retval int
+ *    The offset in the comment array of the first comment whose field
+ *    name matches \a field_name, or \c -1 if no match was found.
+ */
+FLAC_API int FLAC__metadata_object_vorbiscomment_find_entry_from(const FLAC__StreamMetadata *object, unsigned offset, const char *field_name);
+
+/*@@@@ add to unit tests */
+/** Remove first Vorbis comment matching the given field name.
+ *
+ * \param object      A pointer to an existing VORBIS_COMMENT object.
+ * \param field_name  The field name of comment to delete.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
+ * \retval int
+ *    \c -1 for memory allocation error, \c 0 for no matching entries,
+ *    \c 1 for one matching entry deleted.
+ */
+FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entry_matching(FLAC__StreamMetadata *object, const char *field_name);
+
+/*@@@@ add to unit tests */
+/** Remove all Vorbis comments matching the given field name.
+ *
+ * \param object      A pointer to an existing VORBIS_COMMENT object.
+ * \param field_name  The field name of comments to delete.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
+ * \retval int
+ *    \c -1 for memory allocation error, \c 0 for no matching entries,
+ *    else the number of matching entries deleted.
+ */
+FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entries_matching(FLAC__StreamMetadata *object, const char *field_name);
+
+/** Create a new CUESHEET track instance.
+ *
+ *  The object will be "empty"; i.e. values and data pointers will be \c 0.
+ *
+ * \retval FLAC__StreamMetadata_CueSheet_Track*
+ *    \c NULL if there was an error allocating memory, else the new instance.
+ */
+FLAC_API FLAC__StreamMetadata_CueSheet_Track *FLAC__metadata_object_cuesheet_track_new();
+
+/** Create a copy of an existing CUESHEET track object.
+ *
+ *  The copy is a "deep" copy, i.e. dynamically allocated data within the
+ *  object is also copied.  The caller takes ownership of the new object and
+ *  is responsible for freeing it with
+ *  FLAC__metadata_object_cuesheet_track_delete().
+ *
+ * \param object  Pointer to object to copy.
+ * \assert
+ *    \code object != NULL \endcode
+ * \retval FLAC__StreamMetadata_CueSheet_Track*
+ *    \c NULL if there was an error allocating memory, else the new instance.
+ */
+FLAC_API FLAC__StreamMetadata_CueSheet_Track *FLAC__metadata_object_cuesheet_track_clone(const FLAC__StreamMetadata_CueSheet_Track *object);
+
+/** Delete a CUESHEET track object
+ *
+ * \param object       A pointer to an existing CUESHEET track object.
+ * \assert
+ *    \code object != NULL \endcode
+ */
+FLAC_API void FLAC__metadata_object_cuesheet_track_delete(FLAC__StreamMetadata_CueSheet_Track *object);
+
+/** Resize a track's index point array.
+ *
+ *  If the size shrinks, elements will truncated; if it grows, new blank
+ *  indices will be added to the end.
+ *
+ * \param object           A pointer to an existing CUESHEET object.
+ * \param track_num        The index of the track to modify.  NOTE: this is not
+ *                         necessarily the same as the track's \a number field.
+ * \param new_num_indices  The desired length of the array; may be \c 0.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ *    \code object->data.cue_sheet.num_tracks > track_num \endcode
+ *    \code (object->data.cue_sheet.tracks[track_num].indices == NULL && object->data.cue_sheet.tracks[track_num].num_indices == 0) ||
+ * (object->data.cue_sheet.tracks[track_num].indices != NULL && object->data.cue_sheet.tracks[track_num].num_indices > 0) \endcode
+ * \retval FLAC__bool
+ *    \c false if memory allocation error, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_resize_indices(FLAC__StreamMetadata *object, unsigned track_num, unsigned new_num_indices);
+
+/** Insert an index point in a CUESHEET track at the given index.
+ *
+ * \param object       A pointer to an existing CUESHEET object.
+ * \param track_num    The index of the track to modify.  NOTE: this is not
+ *                     necessarily the same as the track's \a number field.
+ * \param index_num    The index into the track's index array at which to
+ *                     insert the index point.  NOTE: this is not necessarily
+ *                     the same as the index point's \a number field.  The
+ *                     indices at and after \a index_num move right one
+ *                     position.  To append an index point to the end, set
+ *                     \a index_num to
+ *                     \c object->data.cue_sheet.tracks[track_num].num_indices .
+ * \param index        The index point to insert.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ *    \code object->data.cue_sheet.num_tracks > track_num \endcode
+ *    \code object->data.cue_sheet.tracks[track_num].num_indices >= index_num \endcode
+ * \retval FLAC__bool
+ *    \c false if realloc fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_index(FLAC__StreamMetadata *object, unsigned track_num, unsigned index_num, FLAC__StreamMetadata_CueSheet_Index index);
+
+/** Insert a blank index point in a CUESHEET track at the given index.
+ *
+ *  A blank index point is one in which all field values are zero.
+ *
+ * \param object       A pointer to an existing CUESHEET object.
+ * \param track_num    The index of the track to modify.  NOTE: this is not
+ *                     necessarily the same as the track's \a number field.
+ * \param index_num    The index into the track's index array at which to
+ *                     insert the index point.  NOTE: this is not necessarily
+ *                     the same as the index point's \a number field.  The
+ *                     indices at and after \a index_num move right one
+ *                     position.  To append an index point to the end, set
+ *                     \a index_num to
+ *                     \c object->data.cue_sheet.tracks[track_num].num_indices .
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ *    \code object->data.cue_sheet.num_tracks > track_num \endcode
+ *    \code object->data.cue_sheet.tracks[track_num].num_indices >= index_num \endcode
+ * \retval FLAC__bool
+ *    \c false if realloc fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_blank_index(FLAC__StreamMetadata *object, unsigned track_num, unsigned index_num);
+
+/** Delete an index point in a CUESHEET track at the given index.
+ *
+ * \param object       A pointer to an existing CUESHEET object.
+ * \param track_num    The index into the track array of the track to
+ *                     modify.  NOTE: this is not necessarily the same
+ *                     as the track's \a number field.
+ * \param index_num    The index into the track's index array of the index
+ *                     to delete.  NOTE: this is not necessarily the same
+ *                     as the index's \a number field.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ *    \code object->data.cue_sheet.num_tracks > track_num \endcode
+ *    \code object->data.cue_sheet.tracks[track_num].num_indices > index_num \endcode
+ * \retval FLAC__bool
+ *    \c false if realloc fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_delete_index(FLAC__StreamMetadata *object, unsigned track_num, unsigned index_num);
+
+/** Resize the track array.
+ *
+ *  If the size shrinks, elements will truncated; if it grows, new blank
+ *  tracks will be added to the end.
+ *
+ * \param object            A pointer to an existing CUESHEET object.
+ * \param new_num_tracks    The desired length of the array; may be \c 0.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ *    \code (object->data.cue_sheet.tracks == NULL && object->data.cue_sheet.num_tracks == 0) ||
+ * (object->data.cue_sheet.tracks != NULL && object->data.cue_sheet.num_tracks > 0) \endcode
+ * \retval FLAC__bool
+ *    \c false if memory allocation error, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_resize_tracks(FLAC__StreamMetadata *object, unsigned new_num_tracks);
+
+/** Sets a track in a CUESHEET block.
+ *
+ *  If \a copy is \c true, a copy of the track is stored; otherwise, the object
+ *  takes ownership of the \a track pointer.  Returns \c false if
+ *  \a copy == \c true and malloc fails.
+ *
+ * \param object       A pointer to an existing CUESHEET object.
+ * \param track_num    Index into track array to set.  NOTE: this is not
+ *                     necessarily the same as the track's \a number field.
+ * \param track        The track to set the track to.  You may safely pass in
+ *                     a const pointer if \a copy is \c true.
+ * \param copy         See above.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ *    \code track_num < object->data.cue_sheet.num_tracks \endcode
+ *    \code (track->indices != NULL && track->num_indices > 0) ||
+ * (track->indices == NULL && track->num_indices == 0)
+ * \retval FLAC__bool
+ *    \c false if \a copy is \c true and malloc fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_set_track(FLAC__StreamMetadata *object, unsigned track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy);
+
+/** Insert a track in a CUESHEET block at the given index.
+ *
+ *  If \a copy is \c true, a copy of the track is stored; otherwise, the object
+ *  takes ownership of the \a track pointer.  Returns \c false if
+ *  \a copy == \c true and malloc fails.
+ *
+ * \param object       A pointer to an existing CUESHEET object.
+ * \param track_num    The index at which to insert the track.  NOTE: this
+ *                     is not necessarily the same as the track's \a number
+ *                     field.  The tracks at and after \a track_num move right
+ *                     one position.  To append a track to the end, set
+ *                     \a track_num to \c object->data.cue_sheet.num_tracks .
+ * \param track        The track to insert.  You may safely pass in a const
+ *                     pointer if \a copy is \c true.
+ * \param copy         See above.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ *    \code object->data.cue_sheet.num_tracks >= track_num \endcode
+ * \retval FLAC__bool
+ *    \c false if \a copy is \c true and malloc fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_track(FLAC__StreamMetadata *object, unsigned track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy);
+
+/** Insert a blank track in a CUESHEET block at the given index.
+ *
+ *  A blank track is one in which all field values are zero.
+ *
+ * \param object       A pointer to an existing CUESHEET object.
+ * \param track_num    The index at which to insert the track.  NOTE: this
+ *                     is not necessarily the same as the track's \a number
+ *                     field.  The tracks at and after \a track_num move right
+ *                     one position.  To append a track to the end, set
+ *                     \a track_num to \c object->data.cue_sheet.num_tracks .
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ *    \code object->data.cue_sheet.num_tracks >= track_num \endcode
+ * \retval FLAC__bool
+ *    \c false if \a copy is \c true and malloc fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_blank_track(FLAC__StreamMetadata *object, unsigned track_num);
+
+/** Delete a track in a CUESHEET block at the given index.
+ *
+ * \param object       A pointer to an existing CUESHEET object.
+ * \param track_num    The index into the track array of the track to
+ *                     delete.  NOTE: this is not necessarily the same
+ *                     as the track's \a number field.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ *    \code object->data.cue_sheet.num_tracks > track_num \endcode
+ * \retval FLAC__bool
+ *    \c false if realloc fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_delete_track(FLAC__StreamMetadata *object, unsigned track_num);
+
+/** Check a cue sheet to see if it conforms to the FLAC specification.
+ *  See the format specification for limits on the contents of the
+ *  cue sheet.
+ *
+ * \param object     A pointer to an existing CUESHEET object.
+ * \param check_cd_da_subset  If \c true, check CUESHEET against more
+ *                   stringent requirements for a CD-DA (audio) disc.
+ * \param violation  Address of a pointer to a string.  If there is a
+ *                   violation, a pointer to a string explanation of the
+ *                   violation will be returned here. \a violation may be
+ *                   \c NULL if you don't need the returned string.  Do not
+ *                   free the returned string; it will always point to static
+ *                   data.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ * \retval FLAC__bool
+ *    \c false if cue sheet is illegal, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_is_legal(const FLAC__StreamMetadata *object, FLAC__bool check_cd_da_subset, const char **violation);
+
+/* \} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/FLAC/ordinals.h
@@ -1,0 +1,81 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__ORDINALS_H
+#define FLAC__ORDINALS_H
+
+#if !defined(_MSC_VER) && !defined(Plan9)
+#include <inttypes.h>
+#endif
+
+typedef signed char FLAC__int8;
+typedef unsigned char FLAC__uint8;
+
+#if defined _MSC_VER
+typedef __int16 FLAC__int16;
+typedef __int32 FLAC__int32;
+typedef __int64 FLAC__int64;
+typedef unsigned __int16 FLAC__uint16;
+typedef unsigned __int32 FLAC__uint32;
+typedef unsigned __int64 FLAC__uint64;
+#elif defined Plan9
+typedef short FLAC__int16;
+typedef int FLAC__int32;
+typedef long long FLAC__int64;
+typedef unsigned short FLAC__uint16;
+typedef unsigned int FLAC__uint32;
+typedef unsigned long long FLAC__uint64;
+#else
+typedef int16_t FLAC__int16;
+typedef int32_t FLAC__int32;
+typedef int64_t FLAC__int64;
+typedef uint16_t FLAC__uint16;
+typedef uint32_t FLAC__uint32;
+typedef uint64_t FLAC__uint64;
+#endif
+
+typedef int FLAC__bool;
+
+typedef FLAC__uint8 FLAC__byte;
+typedef float FLAC__real;
+
+#ifdef true
+#undef true
+#endif
+#ifdef false
+#undef false
+#endif
+#ifndef __cplusplus
+#define true 1
+#define false 0
+#endif
+
+#endif
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/FLAC/seekable_stream_decoder.h
@@ -1,0 +1,931 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__SEEKABLE_STREAM_DECODER_H
+#define FLAC__SEEKABLE_STREAM_DECODER_H
+
+#include "export.h"
+#include "stream_decoder.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** \file include/FLAC/seekable_stream_decoder.h
+ *
+ *  \brief
+ *  This module contains the functions which implement the seekable stream
+ *  decoder.
+ *
+ *  See the detailed documentation in the
+ *  \link flac_seekable_stream_decoder seekable stream decoder \endlink module.
+ */
+
+/** \defgroup flac_seekable_stream_decoder FLAC/seekable_stream_decoder.h: seekable stream decoder interface
+ *  \ingroup flac_decoder
+ *
+ *  \brief
+ *  This module contains the functions which implement the seekable stream
+ *  decoder.
+ *
+ * The basic usage of this decoder is as follows:
+ * - The program creates an instance of a decoder using
+ *   FLAC__seekable_stream_decoder_new().
+ * - The program overrides the default settings and sets callbacks for
+ *   reading, writing, seeking, error reporting, and metadata reporting
+ *   using FLAC__seekable_stream_decoder_set_*() functions.
+ * - The program initializes the instance to validate the settings and
+ *   prepare for decoding using FLAC__seekable_stream_decoder_init().
+ * - The program calls the FLAC__seekable_stream_decoder_process_*()
+ *   functions to decode data, which subsequently calls the callbacks.
+ * - The program finishes the decoding with
+ *   FLAC__seekable_stream_decoder_finish(), which flushes the input and
+ *   output and resets the decoder to the uninitialized state.
+ * - The instance may be used again or deleted with
+ *   FLAC__seekable_stream_decoder_delete().
+ *
+ * The seekable stream decoder is a wrapper around the
+ * \link flac_stream_decoder stream decoder \endlink which also provides
+ * seeking capability.  In addition to the Read/Write/Metadata/Error
+ * callbacks of the stream decoder, the user must also provide the following:
+ *
+ * - Seek callback - This function will be called when the decoder wants to
+ *   seek to an absolute position in the stream.
+ * - Tell callback - This function will be called when the decoder wants to
+ *   know the current absolute position of the stream.
+ * - Length callback - This function will be called when the decoder wants
+ *   to know length of the stream.  The seeking algorithm currently requires
+ *   that the overall stream length be known.
+ * - EOF callback - This function will be called when the decoder wants to
+ *   know if it is at the end of the stream.  This could be synthesized from
+ *   the tell and length callbacks but it may be more expensive that way, so
+ *   there is a separate callback for it.
+ *
+ * Seeking is exposed through the
+ * FLAC__seekable_stream_decoder_seek_absolute() method.  At any point after
+ * the seekable stream decoder has been initialized, the user can call this
+ * function to seek to an exact sample within the stream.  Subsequently, the
+ * first time the write callback is called it will be passed a (possibly
+ * partial) block starting at that sample.
+ *
+ * The seekable stream decoder also provides MD5 signature checking.  If
+ * this is turned on before initialization,
+ * FLAC__seekable_stream_decoder_finish() will report when the decoded MD5
+ * signature does not match the one stored in the STREAMINFO block.  MD5
+ * checking is automatically turned off (until the next
+ * FLAC__seekable_stream_decoder_reset()) if there is no signature in the
+ * STREAMINFO block or when a seek is attempted.
+ *
+ * Make sure to read the detailed description of the
+ * \link flac_stream_decoder stream decoder module \endlink since the
+ * seekable stream decoder inherits much of its behavior.
+ *
+ * \note
+ * The "set" functions may only be called when the decoder is in the
+ * state FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED, i.e. after
+ * FLAC__seekable_stream_decoder_new() or
+ * FLAC__seekable_stream_decoder_finish(), but before
+ * FLAC__seekable_stream_decoder_init().  If this is the case they will
+ * return \c true, otherwise \c false.
+ *
+ * \note
+ * FLAC__stream_decoder_finish() resets all settings to the constructor
+ * defaults, including the callbacks.
+ *
+ * \{
+ */
+
+
+/** State values for a FLAC__SeekableStreamDecoder
+ *
+ *  The decoder's state can be obtained by calling FLAC__seekable_stream_decoder_get_state().
+ */
+typedef enum {
+
+	FLAC__SEEKABLE_STREAM_DECODER_OK = 0,
+	/**< The decoder is in the normal OK state. */
+
+	FLAC__SEEKABLE_STREAM_DECODER_SEEKING,
+	/**< The decoder is in the process of seeking. */
+
+	FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM,
+	/**< The decoder has reached the end of the stream. */
+
+	FLAC__SEEKABLE_STREAM_DECODER_MEMORY_ALLOCATION_ERROR,
+	/**< An error occurred allocating memory. */
+
+	FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR,
+	/**< An error occurred in the underlying stream decoder. */
+
+	FLAC__SEEKABLE_STREAM_DECODER_READ_ERROR,
+	/**< The read callback returned an error. */
+
+	FLAC__SEEKABLE_STREAM_DECODER_SEEK_ERROR,
+	/**< An error occurred while seeking or the seek or tell
+	 * callback returned an error.
+	 */
+
+	FLAC__SEEKABLE_STREAM_DECODER_ALREADY_INITIALIZED,
+	/**< FLAC__seekable_stream_decoder_init() was called when the
+	 * decoder was already initialized, usually because
+	 * FLAC__seekable_stream_decoder_finish() was not called.
+	 */
+
+	FLAC__SEEKABLE_STREAM_DECODER_INVALID_CALLBACK,
+	/**< FLAC__seekable_stream_decoder_init() was called without all
+	 * callbacks being set.
+	 */
+
+	FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED
+	/**< The decoder is in the uninitialized state. */
+
+} FLAC__SeekableStreamDecoderState;
+
+/** Maps a FLAC__SeekableStreamDecoderState to a C string.
+ *
+ *  Using a FLAC__SeekableStreamDecoderState as the index to this array
+ *  will give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__SeekableStreamDecoderStateString[];
+
+
+/** Return values for the FLAC__SeekableStreamDecoder read callback.
+ */
+typedef enum {
+
+	FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK,
+	/**< The read was OK and decoding can continue. */
+
+	FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_ERROR
+	/**< An unrecoverable error occurred.  The decoder will return from the process call. */
+
+} FLAC__SeekableStreamDecoderReadStatus;
+
+/** Maps a FLAC__SeekableStreamDecoderReadStatus to a C string.
+ *
+ *  Using a FLAC__SeekableStreamDecoderReadStatus as the index to this array
+ *  will give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__SeekableStreamDecoderReadStatusString[];
+
+
+/** Return values for the FLAC__SeekableStreamDecoder seek callback.
+ */
+typedef enum {
+
+	FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK,
+	/**< The seek was OK and decoding can continue. */
+
+	FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR
+	/**< An unrecoverable error occurred.  The decoder will return from the process call. */
+
+} FLAC__SeekableStreamDecoderSeekStatus;
+
+/** Maps a FLAC__SeekableStreamDecoderSeekStatus to a C string.
+ *
+ *  Using a FLAC__SeekableStreamDecoderSeekStatus as the index to this array
+ *  will give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__SeekableStreamDecoderSeekStatusString[];
+
+
+/** Return values for the FLAC__SeekableStreamDecoder tell callback.
+ */
+typedef enum {
+
+	FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK,
+	/**< The tell was OK and decoding can continue. */
+
+	FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_ERROR
+	/**< An unrecoverable error occurred.  The decoder will return from the process call. */
+
+} FLAC__SeekableStreamDecoderTellStatus;
+
+/** Maps a FLAC__SeekableStreamDecoderTellStatus to a C string.
+ *
+ *  Using a FLAC__SeekableStreamDecoderTellStatus as the index to this array
+ *  will give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__SeekableStreamDecoderTellStatusString[];
+
+
+/** Return values for the FLAC__SeekableStreamDecoder length callback.
+ */
+typedef enum {
+
+	FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK,
+	/**< The length call was OK and decoding can continue. */
+
+	FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_ERROR
+	/**< An unrecoverable error occurred.  The decoder will return from the process call. */
+
+} FLAC__SeekableStreamDecoderLengthStatus;
+
+/** Maps a FLAC__SeekableStreamDecoderLengthStatus to a C string.
+ *
+ *  Using a FLAC__SeekableStreamDecoderLengthStatus as the index to this array
+ *  will give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__SeekableStreamDecoderLengthStatusString[];
+
+
+/***********************************************************************
+ *
+ * class FLAC__SeekableStreamDecoder : public FLAC__StreamDecoder
+ *
+ ***********************************************************************/
+
+struct FLAC__SeekableStreamDecoderProtected;
+struct FLAC__SeekableStreamDecoderPrivate;
+/** The opaque structure definition for the seekable stream decoder type.
+ *  See the
+ *  \link flac_seekable_stream_decoder seekable stream decoder module \endlink
+ *  for a detailed description.
+ */
+typedef struct {
+	struct FLAC__SeekableStreamDecoderProtected *protected_; /* avoid the C++ keyword 'protected' */
+	struct FLAC__SeekableStreamDecoderPrivate *private_; /* avoid the C++ keyword 'private' */
+} FLAC__SeekableStreamDecoder;
+
+/** Signature for the read callback.
+ *  See FLAC__seekable_stream_decoder_set_read_callback()
+ *  and FLAC__StreamDecoderReadCallback for more info.
+ *
+ * \param  decoder  The decoder instance calling the callback.
+ * \param  buffer   A pointer to a location for the callee to store
+ *                  data to be decoded.
+ * \param  bytes    A pointer to the size of the buffer.
+ * \param  client_data  The callee's client data set through
+ *                      FLAC__seekable_stream_decoder_set_client_data().
+ * \retval FLAC__SeekableStreamDecoderReadStatus
+ *    The callee's return status.
+ */
+typedef FLAC__SeekableStreamDecoderReadStatus (*FLAC__SeekableStreamDecoderReadCallback)(const FLAC__SeekableStreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data);
+
+/** Signature for the seek callback.
+ *  See FLAC__seekable_stream_decoder_set_seek_callback() for more info.
+ *
+ * \param  decoder  The decoder instance calling the callback.
+ * \param  absolute_byte_offset  The offset from the beginning of the stream
+ *                               to seek to.
+ * \param  client_data  The callee's client data set through
+ *                      FLAC__seekable_stream_decoder_set_client_data().
+ * \retval FLAC__SeekableStreamDecoderSeekStatus
+ *    The callee's return status.
+ */
+typedef FLAC__SeekableStreamDecoderSeekStatus (*FLAC__SeekableStreamDecoderSeekCallback)(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data);
+
+/** Signature for the tell callback.
+ *  See FLAC__seekable_stream_decoder_set_tell_callback() for more info.
+ *
+ * \param  decoder  The decoder instance calling the callback.
+ * \param  absolute_byte_offset  A pointer to storage for the current offset
+ *                               from the beginning of the stream.
+ * \param  client_data  The callee's client data set through
+ *                      FLAC__seekable_stream_decoder_set_client_data().
+ * \retval FLAC__SeekableStreamDecoderTellStatus
+ *    The callee's return status.
+ */
+typedef FLAC__SeekableStreamDecoderTellStatus (*FLAC__SeekableStreamDecoderTellCallback)(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data);
+
+/** Signature for the length callback.
+ *  See FLAC__seekable_stream_decoder_set_length_callback() for more info.
+ *
+ * \param  decoder  The decoder instance calling the callback.
+ * \param  stream_length  A pointer to storage for the length of the stream
+ *                        in bytes.
+ * \param  client_data  The callee's client data set through
+ *                      FLAC__seekable_stream_decoder_set_client_data().
+ * \retval FLAC__SeekableStreamDecoderLengthStatus
+ *    The callee's return status.
+ */
+typedef FLAC__SeekableStreamDecoderLengthStatus (*FLAC__SeekableStreamDecoderLengthCallback)(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data);
+
+/** Signature for the EOF callback.
+ *  See FLAC__seekable_stream_decoder_set_eof_callback() for more info.
+ *
+ * \param  decoder  The decoder instance calling the callback.
+ * \param  client_data  The callee's client data set through
+ *                      FLAC__seekable_stream_decoder_set_client_data().
+ * \retval FLAC__bool
+ *    \c true if the currently at the end of the stream, else \c false.
+ */
+typedef FLAC__bool (*FLAC__SeekableStreamDecoderEofCallback)(const FLAC__SeekableStreamDecoder *decoder, void *client_data);
+
+/** Signature for the write callback.
+ *  See FLAC__seekable_stream_decoder_set_write_callback()
+ *  and FLAC__StreamDecoderWriteCallback for more info.
+ *
+ * \param  decoder  The decoder instance calling the callback.
+ * \param  frame    The description of the decoded frame.
+ * \param  buffer   An array of pointers to decoded channels of data.
+ * \param  client_data  The callee's client data set through
+ *                      FLAC__seekable_stream_decoder_set_client_data().
+ * \retval FLAC__StreamDecoderWriteStatus
+ *    The callee's return status.
+ */
+typedef FLAC__StreamDecoderWriteStatus (*FLAC__SeekableStreamDecoderWriteCallback)(const FLAC__SeekableStreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data);
+
+/** Signature for the metadata callback.
+ *  See FLAC__seekable_stream_decoder_set_metadata_callback()
+ *  and FLAC__StreamDecoderMetadataCallback for more info.
+ *
+ * \param  decoder  The decoder instance calling the callback.
+ * \param  metadata The decoded metadata block.
+ * \param  client_data  The callee's client data set through
+ *                      FLAC__seekable_stream_decoder_set_client_data().
+ */
+typedef void (*FLAC__SeekableStreamDecoderMetadataCallback)(const FLAC__SeekableStreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data);
+
+/** Signature for the error callback.
+ *  See FLAC__seekable_stream_decoder_set_error_callback()
+ *  and FLAC__StreamDecoderErrorCallback for more info.
+ *
+ * \param  decoder  The decoder instance calling the callback.
+ * \param  status   The error encountered by the decoder.
+ * \param  client_data  The callee's client data set through
+ *                      FLAC__seekable_stream_decoder_set_client_data().
+ */
+typedef void (*FLAC__SeekableStreamDecoderErrorCallback)(const FLAC__SeekableStreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
+
+
+/***********************************************************************
+ *
+ * Class constructor/destructor
+ *
+ ***********************************************************************/
+
+/** Create a new seekable stream decoder instance.  The instance is created
+ *  with default settings; see the individual
+ *  FLAC__seekable_stream_decoder_set_*() functions for each setting's
+ *  default.
+ *
+ * \retval FLAC__SeekableStreamDecoder*
+ *    \c NULL if there was an error allocating memory, else the new instance.
+ */
+FLAC_API FLAC__SeekableStreamDecoder *FLAC__seekable_stream_decoder_new();
+
+/** Free a decoder instance.  Deletes the object pointed to by \a decoder.
+ *
+ * \param decoder  A pointer to an existing decoder.
+ * \assert
+ *    \code decoder != NULL \endcode
+ */
+FLAC_API void FLAC__seekable_stream_decoder_delete(FLAC__SeekableStreamDecoder *decoder);
+
+
+/***********************************************************************
+ *
+ * Public class method prototypes
+ *
+ ***********************************************************************/
+
+/** Set the "MD5 signature checking" flag.  If \c true, the decoder will
+ *  compute the MD5 signature of the unencoded audio data while decoding
+ *  and compare it to the signature from the STREAMINFO block, if it
+ *  exists, during FLAC__seekable_stream_decoder_finish().
+ *
+ *  MD5 signature checking will be turned off (until the next
+ *  FLAC__seekable_stream_decoder_reset()) if there is no signature in
+ *  the STREAMINFO block or when a seek is attempted.
+ *
+ * \default \c false
+ * \param  decoder  A decoder instance to set.
+ * \param  value    Flag value (see above).
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_md5_checking(FLAC__SeekableStreamDecoder *decoder, FLAC__bool value);
+
+/** Set the read callback.
+ *  This is inherited from FLAC__StreamDecoder; see
+ *  FLAC__stream_decoder_set_read_callback().
+ *
+ * \note
+ * The callback is mandatory and must be set before initialization.
+ *
+ * \default \c NULL
+ * \param  decoder  A decoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code decoder != NULL \endcode
+ *    \code value != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_read_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderReadCallback value);
+
+/** Set the seek callback.
+ *  The supplied function will be called when the decoder needs to seek
+ *  the input stream.  The decoder will pass the absolute byte offset
+ *  to seek to, 0 meaning the beginning of the stream.
+ *
+ * \note
+ * The callback is mandatory and must be set before initialization.
+ *
+ * \default \c NULL
+ * \param  decoder  A decoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code decoder != NULL \endcode
+ *    \code value != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_seek_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderSeekCallback value);
+
+/** Set the tell callback.
+ *  The supplied function will be called when the decoder wants to know
+ *  the current position of the stream.  The callback should return the
+ *  byte offset from the beginning of the stream.
+ *
+ * \note
+ * The callback is mandatory and must be set before initialization.
+ *
+ * \default \c NULL
+ * \param  decoder  A decoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code decoder != NULL \endcode
+ *    \code value != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_tell_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderTellCallback value);
+
+/** Set the length callback.
+ *  The supplied function will be called when the decoder wants to know
+ *  the total length of the stream in bytes.
+ *
+ * \note
+ * The callback is mandatory and must be set before initialization.
+ *
+ * \default \c NULL
+ * \param  decoder  A decoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code decoder != NULL \endcode
+ *    \code value != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_length_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderLengthCallback value);
+
+/** Set the eof callback.
+ *  The supplied function will be called when the decoder needs to know
+ *  if the end of the stream has been reached.
+ *
+ * \note
+ * The callback is mandatory and must be set before initialization.
+ *
+ * \default \c NULL
+ * \param  decoder  A decoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code decoder != NULL \endcode
+ *    \code value != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_eof_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderEofCallback value);
+
+/** Set the write callback.
+ *  This is inherited from FLAC__StreamDecoder; see
+ *  FLAC__stream_decoder_set_write_callback().
+ *
+ * \note
+ * The callback is mandatory and must be set before initialization.
+ *
+ * \default \c NULL
+ * \param  decoder  A decoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code decoder != NULL \endcode
+ *    \code value != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_write_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderWriteCallback value);
+
+/** Set the metadata callback.
+ *  This is inherited from FLAC__StreamDecoder; see
+ *  FLAC__stream_decoder_set_metadata_callback().
+ *
+ * \note
+ * The callback is mandatory and must be set before initialization.
+ *
+ * \default \c NULL
+ * \param  decoder  A decoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code decoder != NULL \endcode
+ *    \code value != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_metadata_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderMetadataCallback value);
+
+/** Set the error callback.
+ *  This is inherited from FLAC__StreamDecoder; see
+ *  FLAC__stream_decoder_set_error_callback().
+ *
+ * \note
+ * The callback is mandatory and must be set before initialization.
+ *
+ * \default \c NULL
+ * \param  decoder  A decoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code decoder != NULL \endcode
+ *    \code value != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_error_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderErrorCallback value);
+
+/** Set the client data to be passed back to callbacks.
+ *  This value will be supplied to callbacks in their \a client_data
+ *  argument.
+ *
+ * \default \c NULL
+ * \param  decoder  A decoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_client_data(FLAC__SeekableStreamDecoder *decoder, void *value);
+
+/** This is inherited from FLAC__StreamDecoder; see
+ *  FLAC__stream_decoder_set_metadata_respond().
+ *
+ * \default By default, only the \c STREAMINFO block is returned via the
+ *          metadata callback.
+ * \param  decoder  A decoder instance to set.
+ * \param  type     See above.
+ * \assert
+ *    \code decoder != NULL \endcode
+ *    \a type is valid
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_metadata_respond(FLAC__SeekableStreamDecoder *decoder, FLAC__MetadataType type);
+
+/** This is inherited from FLAC__StreamDecoder; see
+ *  FLAC__stream_decoder_set_metadata_respond_application().
+ *
+ * \default By default, only the \c STREAMINFO block is returned via the
+ *          metadata callback.
+ * \param  decoder  A decoder instance to set.
+ * \param  id       See above.
+ * \assert
+ *    \code decoder != NULL \endcode
+ *    \code id != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_metadata_respond_application(FLAC__SeekableStreamDecoder *decoder, const FLAC__byte id[4]);
+
+/** This is inherited from FLAC__StreamDecoder; see
+ *  FLAC__stream_decoder_set_metadata_respond_all().
+ *
+ * \default By default, only the \c STREAMINFO block is returned via the
+ *          metadata callback.
+ * \param  decoder  A decoder instance to set.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_metadata_respond_all(FLAC__SeekableStreamDecoder *decoder);
+
+/** This is inherited from FLAC__StreamDecoder; see
+ *  FLAC__stream_decoder_set_metadata_ignore().
+ *
+ * \default By default, only the \c STREAMINFO block is returned via the
+ *          metadata callback.
+ * \param  decoder  A decoder instance to set.
+ * \param  type     See above.
+ * \assert
+ *    \code decoder != NULL \endcode
+ *    \a type is valid
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_metadata_ignore(FLAC__SeekableStreamDecoder *decoder, FLAC__MetadataType type);
+
+/** This is inherited from FLAC__StreamDecoder; see
+ *  FLAC__stream_decoder_set_metadata_ignore_application().
+ *
+ * \default By default, only the \c STREAMINFO block is returned via the
+ *          metadata callback.
+ * \param  decoder  A decoder instance to set.
+ * \param  id       See above.
+ * \assert
+ *    \code decoder != NULL \endcode
+ *    \code id != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_metadata_ignore_application(FLAC__SeekableStreamDecoder *decoder, const FLAC__byte id[4]);
+
+/** This is inherited from FLAC__StreamDecoder; see
+ *  FLAC__stream_decoder_set_metadata_ignore_all().
+ *
+ * \default By default, only the \c STREAMINFO block is returned via the
+ *          metadata callback.
+ * \param  decoder  A decoder instance to set.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_metadata_ignore_all(FLAC__SeekableStreamDecoder *decoder);
+
+/** Get the current decoder state.
+ *
+ * \param  decoder  A decoder instance to query.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__SeekableStreamDecoderState
+ *    The current decoder state.
+ */
+FLAC_API FLAC__SeekableStreamDecoderState FLAC__seekable_stream_decoder_get_state(const FLAC__SeekableStreamDecoder *decoder);
+
+/** Get the state of the underlying stream decoder.
+ *  Useful when the seekable stream decoder state is
+ *  \c FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR.
+ *
+ * \param  decoder  A decoder instance to query.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__StreamDecoderState
+ *    The stream decoder state.
+ */
+FLAC_API FLAC__StreamDecoderState FLAC__seekable_stream_decoder_get_stream_decoder_state(const FLAC__SeekableStreamDecoder *decoder);
+
+/** Get the current decoder state as a C string.
+ *  This version automatically resolves
+ *  \c FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR by getting the
+ *  stream decoder's state.
+ *
+ * \param  decoder  A decoder instance to query.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval const char *
+ *    The decoder state as a C string.  Do not modify the contents.
+ */
+FLAC_API const char *FLAC__seekable_stream_decoder_get_resolved_state_string(const FLAC__SeekableStreamDecoder *decoder);
+
+/** Get the "MD5 signature checking" flag.
+ *  This is the value of the setting, not whether or not the decoder is
+ *  currently checking the MD5 (remember, it can be turned off automatically
+ *  by a seek).  When the decoder is reset the flag will be restored to the
+ *  value returned by this function.
+ *
+ * \param  decoder  A decoder instance to query.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See above.
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_decoder_get_md5_checking(const FLAC__SeekableStreamDecoder *decoder);
+
+/** This is inherited from FLAC__StreamDecoder; see
+ *  FLAC__stream_decoder_get_channels().
+ *
+ * \param  decoder  A decoder instance to query.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval unsigned
+ *    See above.
+ */
+FLAC_API unsigned FLAC__seekable_stream_decoder_get_channels(const FLAC__SeekableStreamDecoder *decoder);
+
+/** This is inherited from FLAC__StreamDecoder; see
+ *  FLAC__stream_decoder_get_channel_assignment().
+ *
+ * \param  decoder  A decoder instance to query.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__ChannelAssignment
+ *    See above.
+ */
+FLAC_API FLAC__ChannelAssignment FLAC__seekable_stream_decoder_get_channel_assignment(const FLAC__SeekableStreamDecoder *decoder);
+
+/** This is inherited from FLAC__StreamDecoder; see
+ *  FLAC__stream_decoder_get_bits_per_sample().
+ *
+ * \param  decoder  A decoder instance to query.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval unsigned
+ *    See above.
+ */
+FLAC_API unsigned FLAC__seekable_stream_decoder_get_bits_per_sample(const FLAC__SeekableStreamDecoder *decoder);
+
+/** This is inherited from FLAC__StreamDecoder; see
+ *  FLAC__stream_decoder_get_sample_rate().
+ *
+ * \param  decoder  A decoder instance to query.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval unsigned
+ *    See above.
+ */
+FLAC_API unsigned FLAC__seekable_stream_decoder_get_sample_rate(const FLAC__SeekableStreamDecoder *decoder);
+
+/** This is inherited from FLAC__StreamDecoder; see
+ *  FLAC__stream_decoder_get_blocksize().
+ *
+ * \param  decoder  A decoder instance to query.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval unsigned
+ *    See above.
+ */
+FLAC_API unsigned FLAC__seekable_stream_decoder_get_blocksize(const FLAC__SeekableStreamDecoder *decoder);
+
+/** Returns the decoder's current read position within the stream.
+ *  The position is the byte offset from the start of the stream.
+ *  Bytes before this position have been fully decoded.  Note that
+ *  there may still be undecoded bytes in the decoder's read FIFO.
+ *  The returned position is correct even after a seek.
+ *
+ * \param  decoder   A decoder instance to query.
+ * \param  position  Address at which to return the desired position.
+ * \assert
+ *    \code decoder != NULL \endcode
+ *    \code position != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if successful, \c false if there was an error from
+ *    the 'tell' callback.
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_decoder_get_decode_position(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *position);
+
+/** Initialize the decoder instance.
+ *  Should be called after FLAC__seekable_stream_decoder_new() and
+ *  FLAC__seekable_stream_decoder_set_*() but before any of the
+ *  FLAC__seekable_stream_decoder_process_*() functions.  Will set and return
+ *  the decoder state, which will be FLAC__SEEKABLE_STREAM_DECODER_OK
+ *  if initialization succeeded.
+ *
+ * \param  decoder  An uninitialized decoder instance.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__SeekableStreamDecoderState
+ *    \c FLAC__SEEKABLE_STREAM_DECODER_OK if initialization was
+ *    successful; see FLAC__SeekableStreamDecoderState for the meanings
+ *    of other return values.
+ */
+FLAC_API FLAC__SeekableStreamDecoderState FLAC__seekable_stream_decoder_init(FLAC__SeekableStreamDecoder *decoder);
+
+/** Finish the decoding process.
+ *  Flushes the decoding buffer, releases resources, resets the decoder
+ *  settings to their defaults, and returns the decoder state to
+ *  FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED.
+ *
+ *  In the event of a prematurely-terminated decode, it is not strictly
+ *  necessary to call this immediately before
+ *  FLAC__seekable_stream_decoder_delete() but it is good practice to match
+ *  every FLAC__seekable_stream_decoder_init() with a
+ *  FLAC__seekable_stream_decoder_finish().
+ *
+ * \param  decoder  An uninitialized decoder instance.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if MD5 checking is on AND a STREAMINFO block was available
+ *    AND the MD5 signature in the STREAMINFO block was non-zero AND the
+ *    signature does not match the one computed by the decoder; else
+ *    \c true.
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_decoder_finish(FLAC__SeekableStreamDecoder *decoder);
+
+/** Flush the stream input.
+ *  The decoder's input buffer will be cleared and the state set to
+ *  \c FLAC__SEEKABLE_STREAM_DECODER_OK.  This will also turn off MD5
+ *  checking.
+ *
+ * \param  decoder  A decoder instance.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if successful, else \c false if a memory allocation
+ *    or stream decoder error occurs.
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_decoder_flush(FLAC__SeekableStreamDecoder *decoder);
+
+/** Reset the decoding process.
+ *  The decoder's input buffer will be cleared and the state set to
+ *  \c FLAC__SEEKABLE_STREAM_DECODER_OK.  This is similar to
+ *  FLAC__seekable_stream_decoder_finish() except that the settings are
+ *  preserved; there is no need to call FLAC__seekable_stream_decoder_init()
+ *  before decoding again.  MD5 checking will be restored to its original
+ *  setting.
+ *
+ * \param  decoder  A decoder instance.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if successful, else \c false if a memory allocation
+ *    or stream decoder error occurs.
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_decoder_reset(FLAC__SeekableStreamDecoder *decoder);
+
+/** This is inherited from FLAC__StreamDecoder; see
+ *  FLAC__stream_decoder_process_single().
+ *
+ * \param  decoder  A decoder instance.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See above.
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_decoder_process_single(FLAC__SeekableStreamDecoder *decoder);
+
+/** This is inherited from FLAC__StreamDecoder; see
+ *  FLAC__stream_decoder_process_until_end_of_metadata().
+ *
+ * \param  decoder  A decoder instance.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See above.
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_decoder_process_until_end_of_metadata(FLAC__SeekableStreamDecoder *decoder);
+
+/** This is inherited from FLAC__StreamDecoder; see
+ *  FLAC__stream_decoder_process_until_end_of_stream().
+ *
+ * \param  decoder  A decoder instance.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See above.
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_decoder_process_until_end_of_stream(FLAC__SeekableStreamDecoder *decoder);
+
+/** This is inherited from FLAC__StreamDecoder; see
+ *  FLAC__stream_decoder_skip_single_frame().
+ *
+ * \param  decoder  A decoder instance.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See above.
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_decoder_skip_single_frame(FLAC__SeekableStreamDecoder *decoder);
+
+/** Flush the input and seek to an absolute sample.
+ *  Decoding will resume at the given sample.  Note that because of
+ *  this, the next write callback may contain a partial block.
+ *
+ * \param  decoder  A decoder instance.
+ * \param  sample   The target sample number to seek to.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if successful, else \c false.
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_decoder_seek_absolute(FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 sample);
+
+/* \} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/FLAC/seekable_stream_encoder.h
@@ -1,0 +1,992 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2002,2003,2004  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__SEEKABLE_STREAM_ENCODER_H
+#define FLAC__SEEKABLE_STREAM_ENCODER_H
+
+#include "export.h"
+#include "stream_encoder.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** \file include/FLAC/seekable_stream_encoder.h
+ *
+ *  \brief
+ *  This module contains the functions which implement the seekable stream
+ *  encoder.
+ *
+ *  See the detailed documentation in the
+ *  \link flac_seekable_stream_encoder seekable stream encoder \endlink module.
+ */
+
+/** \defgroup flac_seekable_stream_encoder FLAC/seekable_stream_encoder.h: seekable stream encoder interface
+ *  \ingroup flac_encoder
+ *
+ *  \brief
+ *  This module contains the functions which implement the seekable stream
+ *  encoder.
+ *
+ * The basic usage of this encoder is as follows:
+ * - The program creates an instance of an encoder using
+ *   FLAC__seekable_stream_encoder_new().
+ * - The program overrides the default settings and sets callbacks using
+ *   FLAC__seekable_stream_encoder_set_*() functions.
+ * - The program initializes the instance to validate the settings and
+ *   prepare for encoding using FLAC__seekable_stream_encoder_init().
+ * - The program calls FLAC__seekable_stream_encoder_process() or
+ *   FLAC__seekable_stream_encoder_process_interleaved() to encode data, which
+ *   subsequently calls the callbacks when there is encoder data ready
+ *   to be written.
+ * - The program finishes the encoding with FLAC__seekable_stream_encoder_finish(),
+ *   which causes the encoder to encode any data still in its input pipe,
+ *   rewrite the metadata with the final encoding statistics, and finally
+ *   reset the encoder to the uninitialized state.
+ * - The instance may be used again or deleted with
+ *   FLAC__seekable_stream_encoder_delete().
+ *
+ * The seekable stream encoder is a wrapper around the
+ * \link flac_stream_encoder stream encoder \endlink with callbacks for
+ * seeking the output and reporting the output stream position.  This
+ * allows the encoder to go back and rewrite some of the metadata after
+ * encoding if necessary, and provides the metadata callback of the stream
+ * encoder internally.  However, you must provide seek and tell callbacks
+ * (see FLAC__seekable_stream_encoder_set_seek_callback() and
+ * FLAC__seekable_stream_encoder_set_tell_callback()).
+ *
+ * Make sure to read the detailed description of the
+ * \link flac_stream_encoder stream encoder module \endlink since the
+ * seekable stream encoder inherits much of its behavior.
+ *
+ * \note
+ * If you are writing the FLAC data to a file, make sure it is open
+ * for update (e.g. mode "w+" for stdio streams).  This is because after
+ * the first encoding pass, the encoder will try to seek back to the
+ * beginning of the stream, to the STREAMINFO block, to write some data
+ * there.
+ *
+ * \note
+ * The "set" functions may only be called when the encoder is in the
+ * state FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED, i.e. after
+ * FLAC__seekable_stream_encoder_new() or FLAC__seekable_stream_encoder_finish(), but
+ * before FLAC__seekable_stream_encoder_init().  If this is the case they will
+ * return \c true, otherwise \c false.
+ *
+ * \note
+ * FLAC__seekable_stream_encoder_finish() resets all settings to the constructor
+ * defaults, including the callbacks.
+ *
+ * \{
+ */
+
+
+/** State values for a FLAC__SeekableStreamEncoder
+ *
+ *  The encoder's state can be obtained by calling FLAC__seekable_stream_encoder_get_state().
+ */
+typedef enum {
+
+	FLAC__SEEKABLE_STREAM_ENCODER_OK = 0,
+	/**< The encoder is in the normal OK state. */
+
+	FLAC__SEEKABLE_STREAM_ENCODER_STREAM_ENCODER_ERROR,
+	/**< An error occurred in the underlying stream encoder;
+	 * check FLAC__seekable_stream_encoder_get_stream_encoder_state().
+	 */
+
+	FLAC__SEEKABLE_STREAM_ENCODER_MEMORY_ALLOCATION_ERROR,
+	/**< Memory allocation failed. */
+
+	FLAC__SEEKABLE_STREAM_ENCODER_WRITE_ERROR,
+	/**< The write callback returned an error. */
+
+	FLAC__SEEKABLE_STREAM_ENCODER_READ_ERROR,
+	/**< The read callback returned an error. */
+
+	FLAC__SEEKABLE_STREAM_ENCODER_SEEK_ERROR,
+	/**< The seek callback returned an error. */
+
+	FLAC__SEEKABLE_STREAM_ENCODER_TELL_ERROR,
+	/**< The tell callback returned an error. */
+
+	FLAC__SEEKABLE_STREAM_ENCODER_ALREADY_INITIALIZED,
+	/**< FLAC__seekable_stream_encoder_init() was called when the encoder was
+	 * already initialized, usually because
+	 * FLAC__seekable_stream_encoder_finish() was not called.
+	 */
+
+	FLAC__SEEKABLE_STREAM_ENCODER_INVALID_CALLBACK,
+	/**< FLAC__seekable_stream_encoder_init() was called without all
+	 * callbacks being set.
+	 */
+
+	FLAC__SEEKABLE_STREAM_ENCODER_INVALID_SEEKTABLE,
+	/**< An invalid seek table was passed is the metadata to
+	 * FLAC__seekable_stream_encoder_set_metadata().
+	 */
+
+	FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED
+	/**< The encoder is in the uninitialized state. */
+
+} FLAC__SeekableStreamEncoderState;
+
+/** Maps a FLAC__SeekableStreamEncoderState to a C string.
+ *
+ *  Using a FLAC__SeekableStreamEncoderState as the index to this array
+ *  will give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__SeekableStreamEncoderStateString[];
+
+
+/** Return values for the FLAC__SeekableStreamEncoder seek callback.
+ */
+typedef enum {
+
+	FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_OK,
+	/**< The seek was OK and encoding can continue. */
+
+	FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_ERROR
+	/**< An unrecoverable error occurred.  The encoder will return from the process call. */
+
+} FLAC__SeekableStreamEncoderSeekStatus;
+
+/** Maps a FLAC__SeekableStreamEncoderSeekStatus to a C string.
+ *
+ *  Using a FLAC__SeekableStreamEncoderSeekStatus as the index to this array
+ *  will give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__SeekableStreamEncoderSeekStatusString[];
+
+
+/** Return values for the FLAC__SeekableStreamEncoder tell callback.
+ */
+typedef enum {
+
+	FLAC__SEEKABLE_STREAM_ENCODER_TELL_STATUS_OK,
+	/**< The tell was OK and encoding can continue. */
+
+	FLAC__SEEKABLE_STREAM_ENCODER_TELL_STATUS_ERROR
+	/**< An unrecoverable error occurred.  The encoder will return from the process call. */
+
+} FLAC__SeekableStreamEncoderTellStatus;
+
+/** Maps a FLAC__SeekableStreamEncoderTellStatus to a C string.
+ *
+ *  Using a FLAC__SeekableStreamEncoderTellStatus as the index to this array
+ *  will give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__SeekableStreamEncoderTellStatusString[];
+
+
+/***********************************************************************
+ *
+ * class FLAC__SeekableStreamEncoder
+ *
+ ***********************************************************************/
+
+struct FLAC__SeekableStreamEncoderProtected;
+struct FLAC__SeekableStreamEncoderPrivate;
+/** The opaque structure definition for the seekable stream encoder type.
+ *  See the \link flac_seekable_stream_encoder seekable stream encoder module \endlink
+ *  for a detailed description.
+ */
+typedef struct {
+	struct FLAC__SeekableStreamEncoderProtected *protected_; /* avoid the C++ keyword 'protected' */
+	struct FLAC__SeekableStreamEncoderPrivate *private_; /* avoid the C++ keyword 'private' */
+} FLAC__SeekableStreamEncoder;
+
+/** Signature for the seek callback.
+ *  See FLAC__seekable_stream_encoder_set_seek_callback() for more info.
+ *
+ * \param  encoder  The encoder instance calling the callback.
+ * \param  absolute_byte_offset  The offset from the beginning of the stream
+ *                               to seek to.
+ * \param  client_data  The callee's client data set through
+ *                      FLAC__seekable_stream_encoder_set_client_data().
+ * \retval FLAC__SeekableStreamEncoderSeekStatus
+ *    The callee's return status.
+ */
+typedef FLAC__SeekableStreamEncoderSeekStatus (*FLAC__SeekableStreamEncoderSeekCallback)(const FLAC__SeekableStreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data);
+
+/** Signature for the tell callback.
+ *  See FLAC__seekable_stream_encoder_set_tell_callback() for more info.
+ *
+ * \warning
+ * The callback must return the true current byte offset of the output to
+ * which the encoder is writing.  If you are buffering the output, make
+ * sure and take this into account.  If you are writing directly to a
+ * FILE* from your write callback, ftell() is sufficient.  If you are
+ * writing directly to a file descriptor from your write callback, you
+ * can use lseek(fd, SEEK_CUR, 0).  The encoder may later seek back to
+ * these points to rewrite metadata after encoding.
+ *
+ * \param  encoder  The encoder instance calling the callback.
+ * \param  absolute_byte_offset  The address at which to store the current
+ *                               position of the output.
+ * \param  client_data  The callee's client data set through
+ *                      FLAC__seekable_stream_encoder_set_client_data().
+ * \retval FLAC__SeekableStreamEncoderTellStatus
+ *    The callee's return status.
+ */
+typedef FLAC__SeekableStreamEncoderTellStatus (*FLAC__SeekableStreamEncoderTellCallback)(const FLAC__SeekableStreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data);
+
+/** Signature for the write callback.
+ *  See FLAC__seekable_stream_encoder_set_write_callback()
+ *  and FLAC__StreamEncoderWriteCallback for more info.
+ *
+ * \param  encoder  The encoder instance calling the callback.
+ * \param  buffer   An array of encoded data of length \a bytes.
+ * \param  bytes    The byte length of \a buffer.
+ * \param  samples  The number of samples encoded by \a buffer.
+ *                  \c 0 has a special meaning; see
+ *                  FLAC__stream_encoder_set_write_callback().
+ * \param  current_frame  The number of current frame being encoded.
+ * \param  client_data  The callee's client data set through
+ *                      FLAC__seekable_stream_encoder_set_client_data().
+ * \retval FLAC__StreamEncoderWriteStatus
+ *    The callee's return status.
+ */
+typedef FLAC__StreamEncoderWriteStatus (*FLAC__SeekableStreamEncoderWriteCallback)(const FLAC__SeekableStreamEncoder *encoder, const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data);
+
+
+/***********************************************************************
+ *
+ * Class constructor/destructor
+ *
+ ***********************************************************************/
+
+/** Create a new seekable stream encoder instance.  The instance is created with
+ *  default settings; see the individual FLAC__seekable_stream_encoder_set_*()
+ *  functions for each setting's default.
+ *
+ * \retval FLAC__SeekableStreamEncoder*
+ *    \c NULL if there was an error allocating memory, else the new instance.
+ */
+FLAC_API FLAC__SeekableStreamEncoder *FLAC__seekable_stream_encoder_new();
+
+/** Free an encoder instance.  Deletes the object pointed to by \a encoder.
+ *
+ * \param encoder  A pointer to an existing encoder.
+ * \assert
+ *    \code encoder != NULL \endcode
+ */
+FLAC_API void FLAC__seekable_stream_encoder_delete(FLAC__SeekableStreamEncoder *encoder);
+
+/***********************************************************************
+ *
+ * Public class method prototypes
+ *
+ ***********************************************************************/
+
+/** This is inherited from FLAC__StreamEncoder; see
+ *  FLAC__stream_encoder_set_verify().
+ *
+ * \default \c true
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_verify(FLAC__SeekableStreamEncoder *encoder, FLAC__bool value);
+
+/** This is inherited from FLAC__StreamEncoder; see
+ *  FLAC__stream_encoder_set_streamable_subset().
+ *
+ * \default \c true
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_streamable_subset(FLAC__SeekableStreamEncoder *encoder, FLAC__bool value);
+
+/** This is inherited from FLAC__StreamEncoder; see
+ *  FLAC__stream_encoder_set_do_mid_side_stereo().
+ *
+ * \default \c false
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_do_mid_side_stereo(FLAC__SeekableStreamEncoder *encoder, FLAC__bool value);
+
+/** This is inherited from FLAC__StreamEncoder; see
+ *  FLAC__stream_encoder_set_loose_mid_side_stereo().
+ *
+ * \default \c false
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_loose_mid_side_stereo(FLAC__SeekableStreamEncoder *encoder, FLAC__bool value);
+
+/** This is inherited from FLAC__StreamEncoder; see
+ *  FLAC__stream_encoder_set_channels().
+ *
+ * \default \c 2
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_channels(FLAC__SeekableStreamEncoder *encoder, unsigned value);
+
+/** This is inherited from FLAC__StreamEncoder; see
+ *  FLAC__stream_encoder_set_bits_per_sample().
+ *
+ * \warning
+ * Do not feed the encoder data that is wider than the value you
+ * set here or you will generate an invalid stream.
+ *
+ * \default \c 16
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_bits_per_sample(FLAC__SeekableStreamEncoder *encoder, unsigned value);
+
+/** This is inherited from FLAC__StreamEncoder; see
+ *  FLAC__stream_encoder_set_sample_rate().
+ *
+ * \default \c 44100
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_sample_rate(FLAC__SeekableStreamEncoder *encoder, unsigned value);
+
+/** This is inherited from FLAC__StreamEncoder; see
+ *  FLAC__stream_encoder_set_blocksize().
+ *
+ * \default \c 1152
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_blocksize(FLAC__SeekableStreamEncoder *encoder, unsigned value);
+
+/** This is inherited from FLAC__StreamEncoder; see
+ *  FLAC__stream_encoder_set_max_lpc_order().
+ *
+ * \default \c 0
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_max_lpc_order(FLAC__SeekableStreamEncoder *encoder, unsigned value);
+
+/** This is inherited from FLAC__StreamEncoder; see
+ *  FLAC__stream_encoder_set_qlp_coeff_precision().
+ *
+ * \note
+ * In the current implementation, qlp_coeff_precision + bits_per_sample must
+ * be less than 32.
+ *
+ * \default \c 0
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_qlp_coeff_precision(FLAC__SeekableStreamEncoder *encoder, unsigned value);
+
+/** This is inherited from FLAC__StreamEncoder; see
+ *  FLAC__stream_encoder_set_do_qlp_coeff_prec_search().
+ *
+ * \default \c false
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_do_qlp_coeff_prec_search(FLAC__SeekableStreamEncoder *encoder, FLAC__bool value);
+
+/** This is inherited from FLAC__StreamEncoder; see
+ *  FLAC__stream_encoder_set_do_escape_coding().
+ *
+ * \default \c false
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_do_escape_coding(FLAC__SeekableStreamEncoder *encoder, FLAC__bool value);
+
+/** This is inherited from FLAC__StreamEncoder; see
+ *  FLAC__stream_encoder_set_do_exhaustive_model_search().
+ *
+ * \default \c false
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_do_exhaustive_model_search(FLAC__SeekableStreamEncoder *encoder, FLAC__bool value);
+
+/** This is inherited from FLAC__StreamEncoder; see
+ *  FLAC__stream_encoder_set_min_residual_partition_order().
+ *
+ * \default \c 0
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_min_residual_partition_order(FLAC__SeekableStreamEncoder *encoder, unsigned value);
+
+/** This is inherited from FLAC__StreamEncoder; see
+ *  FLAC__stream_encoder_set_max_residual_partition_order().
+ *
+ * \default \c 0
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_max_residual_partition_order(FLAC__SeekableStreamEncoder *encoder, unsigned value);
+
+/** This is inherited from FLAC__StreamEncoder; see
+ *  FLAC__stream_encoder_set_rice_parameter_search_dist().
+ *
+ * \default \c 0
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_rice_parameter_search_dist(FLAC__SeekableStreamEncoder *encoder, unsigned value);
+
+/** This is inherited from FLAC__StreamEncoder; see
+ *  FLAC__stream_encoder_set_total_samples_estimate().
+ *
+ * \default \c 0
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_total_samples_estimate(FLAC__SeekableStreamEncoder *encoder, FLAC__uint64 value);
+
+/** This is inherited from FLAC__StreamEncoder; see
+ *  FLAC__stream_encoder_set_metadata().
+ *
+ * \note
+ * SEEKTABLE blocks are handled specially.  Since you will not know
+ * the values for the seek point stream offsets, you should pass in
+ * a SEEKTABLE 'template', that is, a SEEKTABLE object with the
+ * required sample numbers (or placeholder points), with \c 0 for the
+ * \a frame_samples and \a stream_offset fields for each point.  While
+ * encoding, the encoder will fill them in for you and when encoding
+ * is finished, it will seek back and write the real values into the
+ * SEEKTABLE block in the stream.  There are helper routines for
+ * manipulating seektable template blocks; see metadata.h:
+ * FLAC__metadata_object_seektable_template_*().
+ *
+ * \note
+ * The encoder instance \b will modify the first \c SEEKTABLE block
+ * as it transforms the template to a valid seektable while encoding,
+ * but it is still up to the caller to free all metadata blocks after
+ * encoding.
+ *
+ * \default \c NULL, 0
+ * \param  encoder     An encoder instance to set.
+ * \param  metadata    See above.
+ * \param  num_blocks  See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_metadata(FLAC__SeekableStreamEncoder *encoder, FLAC__StreamMetadata **metadata, unsigned num_blocks);
+
+/** Set the seek callback.
+ *  The supplied function will be called when the encoder needs to seek
+ *  the output stream.  The encoder will pass the absolute byte offset
+ *  to seek to, 0 meaning the beginning of the stream.
+ *
+ * \note
+ * The callback is mandatory and must be set before initialization.
+ *
+ * \default \c NULL
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ *    \code value != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_seek_callback(FLAC__SeekableStreamEncoder *encoder, FLAC__SeekableStreamEncoderSeekCallback value);
+
+/** Set the tell callback.
+ *  The supplied function will be called when the encoder needs to know
+ *  the current position of the output stream.
+ *
+ * \note
+ * The callback is mandatory and must be set before initialization.
+ *
+ * \default \c NULL
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ *    \code value != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_tell_callback(FLAC__SeekableStreamEncoder *encoder, FLAC__SeekableStreamEncoderTellCallback value);
+
+/** Set the write callback.
+ *  This is inherited from FLAC__StreamEncoder; see
+ *  FLAC__stream_encoder_set_write_callback().
+ *
+ * \note
+ * The callback is mandatory and must be set before initialization.
+ *
+ * \default \c NULL
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ *    \code value != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_write_callback(FLAC__SeekableStreamEncoder *encoder, FLAC__SeekableStreamEncoderWriteCallback value);
+
+/** Set the client data to be passed back to callbacks.
+ *  This value will be supplied to callbacks in their \a client_data
+ *  argument.
+ *
+ * \default \c NULL
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_client_data(FLAC__SeekableStreamEncoder *encoder, void *value);
+
+/** Get the current encoder state.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__SeekableStreamEncoderState
+ *    The current encoder state.
+ */
+FLAC_API FLAC__SeekableStreamEncoderState FLAC__seekable_stream_encoder_get_state(const FLAC__SeekableStreamEncoder *encoder);
+
+/** Get the state of the underlying stream encoder.
+ *  Useful when the seekable stream encoder state is
+ *  \c FLAC__SEEKABLE_STREAM_ENCODER_STREAM_ENCODER_ERROR.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__StreamEncoderState
+ *    The stream encoder state.
+ */
+FLAC_API FLAC__StreamEncoderState FLAC__seekable_stream_encoder_get_stream_encoder_state(const FLAC__SeekableStreamEncoder *encoder);
+
+/** Get the state of the underlying stream encoder's verify decoder.
+ *  Useful when the seekable stream encoder state is
+ *  \c FLAC__SEEKABLE_STREAM_ENCODER_STREAM_ENCODER_ERROR and the
+ *  stream encoder state is \c FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__StreamDecoderState
+ *    The stream encoder state.
+ */
+FLAC_API FLAC__StreamDecoderState FLAC__seekable_stream_encoder_get_verify_decoder_state(const FLAC__SeekableStreamEncoder *encoder);
+
+/** Get the current encoder state as a C string.
+ *  This version automatically resolves
+ *  \c FLAC__SEEKABLE_STREAM_ENCODER_STREAM_ENCODER_ERROR by getting the
+ *  stream encoder's state.
+ *
+ * \param  encoder  A encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval const char *
+ *    The encoder state as a C string.  Do not modify the contents.
+ */
+FLAC_API const char *FLAC__seekable_stream_encoder_get_resolved_state_string(const FLAC__SeekableStreamEncoder *encoder);
+
+/** Get relevant values about the nature of a verify decoder error.
+ *  Inherited from FLAC__stream_encoder_get_verify_decoder_error_stats().
+ *  Useful when the seekable stream encoder state is
+ *  \c FLAC__SEEKABLE_STREAM_ENCODER_STREAM_ENCODER_ERROR and the
+ *  stream encoder state is
+ *  \c FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \param  absolute_sample  The absolute sample number of the mismatch.
+ * \param  frame_number  The number of the frame in which the mismatch occurred.
+ * \param  channel       The channel in which the mismatch occurred.
+ * \param  sample        The number of the sample (relative to the frame) in
+ *                       which the mismatch occurred.
+ * \param  expected      The expected value for the sample in question.
+ * \param  got           The actual value returned by the decoder.
+ * \assert
+ *    \code encoder != NULL \endcode
+ */
+FLAC_API void FLAC__seekable_stream_encoder_get_verify_decoder_error_stats(const FLAC__SeekableStreamEncoder *encoder, FLAC__uint64 *absolute_sample, unsigned *frame_number, unsigned *channel, unsigned *sample, FLAC__int32 *expected, FLAC__int32 *got);
+
+/** Get the "verify" flag.
+ *  This is inherited from FLAC__StreamEncoder; see
+ *  FLAC__stream_encoder_get_verify().
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See FLAC__seekable_stream_encoder_set_verify().
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_get_verify(const FLAC__SeekableStreamEncoder *encoder);
+
+/** Get the "streamable subset" flag.
+ *  This is inherited from FLAC__StreamEncoder; see
+ *  FLAC__stream_encoder_get_streamable_subset().
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See FLAC__seekable_stream_encoder_set_streamable_subset().
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_get_streamable_subset(const FLAC__SeekableStreamEncoder *encoder);
+
+/** Get the "mid/side stereo coding" flag.
+ *  This is inherited from FLAC__StreamEncoder; see
+ *  FLAC__stream_encoder_get_do_mid_side_stereo().
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See FLAC__seekable_stream_encoder_get_do_mid_side_stereo().
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_get_do_mid_side_stereo(const FLAC__SeekableStreamEncoder *encoder);
+
+/** Get the "adaptive mid/side switching" flag.
+ *  This is inherited from FLAC__StreamEncoder; see
+ *  FLAC__stream_encoder_get_loose_mid_side_stereo().
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See FLAC__seekable_stream_encoder_set_loose_mid_side_stereo().
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_get_loose_mid_side_stereo(const FLAC__SeekableStreamEncoder *encoder);
+
+/** Get the number of input channels being processed.
+ *  This is inherited from FLAC__StreamEncoder; see
+ *  FLAC__stream_encoder_get_channels().
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval unsigned
+ *    See FLAC__seekable_stream_encoder_set_channels().
+ */
+FLAC_API unsigned FLAC__seekable_stream_encoder_get_channels(const FLAC__SeekableStreamEncoder *encoder);
+
+/** Get the input sample resolution setting.
+ *  This is inherited from FLAC__StreamEncoder; see
+ *  FLAC__stream_encoder_get_bits_per_sample().
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval unsigned
+ *    See FLAC__seekable_stream_encoder_set_bits_per_sample().
+ */
+FLAC_API unsigned FLAC__seekable_stream_encoder_get_bits_per_sample(const FLAC__SeekableStreamEncoder *encoder);
+
+/** Get the input sample rate setting.
+ *  This is inherited from FLAC__StreamEncoder; see
+ *  FLAC__stream_encoder_get_sample_rate().
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval unsigned
+ *    See FLAC__seekable_stream_encoder_set_sample_rate().
+ */
+FLAC_API unsigned FLAC__seekable_stream_encoder_get_sample_rate(const FLAC__SeekableStreamEncoder *encoder);
+
+/** Get the blocksize setting.
+ *  This is inherited from FLAC__StreamEncoder; see
+ *  FLAC__stream_encoder_get_blocksize().
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval unsigned
+ *    See FLAC__seekable_stream_encoder_set_blocksize().
+ */
+FLAC_API unsigned FLAC__seekable_stream_encoder_get_blocksize(const FLAC__SeekableStreamEncoder *encoder);
+
+/** Get the maximum LPC order setting.
+ *  This is inherited from FLAC__StreamEncoder; see
+ *  FLAC__stream_encoder_get_max_lpc_order().
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval unsigned
+ *    See FLAC__seekable_stream_encoder_set_max_lpc_order().
+ */
+FLAC_API unsigned FLAC__seekable_stream_encoder_get_max_lpc_order(const FLAC__SeekableStreamEncoder *encoder);
+
+/** Get the quantized linear predictor coefficient precision setting.
+ *  This is inherited from FLAC__StreamEncoder; see
+ *  FLAC__stream_encoder_get_qlp_coeff_precision().
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval unsigned
+ *    See FLAC__seekable_stream_encoder_set_qlp_coeff_precision().
+ */
+FLAC_API unsigned FLAC__seekable_stream_encoder_get_qlp_coeff_precision(const FLAC__SeekableStreamEncoder *encoder);
+
+/** Get the qlp coefficient precision search flag.
+ *  This is inherited from FLAC__StreamEncoder; see
+ *  FLAC__stream_encoder_get_do_qlp_coeff_prec_search().
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See FLAC__seekable_stream_encoder_set_do_qlp_coeff_prec_search().
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_get_do_qlp_coeff_prec_search(const FLAC__SeekableStreamEncoder *encoder);
+
+/** Get the "escape coding" flag.
+ *  This is inherited from FLAC__StreamEncoder; see
+ *  FLAC__stream_encoder_get_do_escape_coding().
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See FLAC__seekable_stream_encoder_set_do_escape_coding().
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_get_do_escape_coding(const FLAC__SeekableStreamEncoder *encoder);
+
+/** Get the exhaustive model search flag.
+ *  This is inherited from FLAC__StreamEncoder; see
+ *  FLAC__stream_encoder_get_do_exhaustive_model_search().
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See FLAC__seekable_stream_encoder_set_do_exhaustive_model_search().
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_get_do_exhaustive_model_search(const FLAC__SeekableStreamEncoder *encoder);
+
+/** Get the minimum residual partition order setting.
+ *  This is inherited from FLAC__StreamEncoder; see
+ *  FLAC__stream_encoder_get_min_residual_partition_order().
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval unsigned
+ *    See FLAC__seekable_stream_encoder_set_min_residual_partition_order().
+ */
+FLAC_API unsigned FLAC__seekable_stream_encoder_get_min_residual_partition_order(const FLAC__SeekableStreamEncoder *encoder);
+
+/** Get maximum residual partition order setting.
+ *  This is inherited from FLAC__StreamEncoder; see
+ *  FLAC__stream_encoder_get_max_residual_partition_order().
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval unsigned
+ *    See FLAC__seekable_stream_encoder_set_max_residual_partition_order().
+ */
+FLAC_API unsigned FLAC__seekable_stream_encoder_get_max_residual_partition_order(const FLAC__SeekableStreamEncoder *encoder);
+
+/** Get the Rice parameter search distance setting.
+ *  This is inherited from FLAC__StreamEncoder; see
+ *  FLAC__stream_encoder_get_rice_parameter_search_dist().
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval unsigned
+ *    See FLAC__seekable_stream_encoder_set_rice_parameter_search_dist().
+ */
+FLAC_API unsigned FLAC__seekable_stream_encoder_get_rice_parameter_search_dist(const FLAC__SeekableStreamEncoder *encoder);
+
+/** Get the previously set estimate of the total samples to be encoded.
+ *  This is inherited from FLAC__StreamEncoder; see
+ *  FLAC__stream_encoder_get_total_samples_estimate().
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__uint64
+ *    See FLAC__seekable_stream_encoder_set_total_samples_estimate().
+ */
+FLAC_API FLAC__uint64 FLAC__seekable_stream_encoder_get_total_samples_estimate(const FLAC__SeekableStreamEncoder *encoder);
+
+/** Initialize the encoder instance.
+ *  Should be called after FLAC__seekable_stream_encoder_new() and
+ *  FLAC__seekable_stream_encoder_set_*() but before FLAC__seekable_stream_encoder_process()
+ *  or FLAC__seekable_stream_encoder_process_interleaved().  Will set and return
+ *  the encoder state, which will be FLAC__SEEKABLE_STREAM_ENCODER_OK if
+ *  initialization succeeded.
+ *
+ *  The call to FLAC__seekable_stream_encoder_init() currently will also immediately
+ *  call the write callback with the \c fLaC signature and all the encoded
+ *  metadata.
+ *
+ * \param  encoder  An uninitialized encoder instance.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__SeekableStreamEncoderState
+ *    \c FLAC__SEEKABLE_STREAM_ENCODER_OK if initialization was successful; see
+ *    FLAC__SeekableStreamEncoderState for the meanings of other return values.
+ */
+FLAC_API FLAC__SeekableStreamEncoderState FLAC__seekable_stream_encoder_init(FLAC__SeekableStreamEncoder *encoder);
+
+/** Finish the encoding process.
+ *  Flushes the encoding buffer, releases resources, resets the encoder
+ *  settings to their defaults, and returns the encoder state to
+ *  FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED.
+ *
+ *  In the event of a prematurely-terminated encode, it is not strictly
+ *  necessary to call this immediately before FLAC__seekable_stream_encoder_delete()
+ *  but it is good practice to match every FLAC__seekable_stream_encoder_init()
+ *  with a FLAC__seekable_stream_encoder_finish().
+ *
+ * \param  encoder  An uninitialized encoder instance.
+ * \assert
+ *    \code encoder != NULL \endcode
+ */
+FLAC_API void FLAC__seekable_stream_encoder_finish(FLAC__SeekableStreamEncoder *encoder);
+
+/** Submit data for encoding.
+ *  This is inherited from FLAC__StreamEncoder; see
+ *  FLAC__stream_encoder_process().
+ *
+ * \param  encoder  An initialized encoder instance in the OK state.
+ * \param  buffer   An array of pointers to each channel's signal.
+ * \param  samples  The number of samples in one channel.
+ * \assert
+ *    \code encoder != NULL \endcode
+ *    \code FLAC__seekable_stream_encoder_get_state(encoder) == FLAC__SEEKABLE_STREAM_ENCODER_OK \endcode
+ * \retval FLAC__bool
+ *    \c true if successful, else \c false; in this case, check the
+ *    encoder state with FLAC__seekable_stream_encoder_get_state() to see what
+ *    went wrong.
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_process(FLAC__SeekableStreamEncoder *encoder, const FLAC__int32 * const buffer[], unsigned samples);
+
+/** Submit data for encoding.
+ *  This is inherited from FLAC__StreamEncoder; see
+ *  FLAC__stream_encoder_process_interleaved().
+ *
+ * \param  encoder  An initialized encoder instance in the OK state.
+ * \param  buffer   An array of channel-interleaved data (see above).
+ * \param  samples  The number of samples in one channel, the same as for
+ *                  FLAC__seekable_stream_encoder_process().  For example, if
+ *                  encoding two channels, \c 1000 \a samples corresponds
+ *                  to a \a buffer of 2000 values.
+ * \assert
+ *    \code encoder != NULL \endcode
+ *    \code FLAC__seekable_stream_encoder_get_state(encoder) == FLAC__SEEKABLE_STREAM_ENCODER_OK \endcode
+ * \retval FLAC__bool
+ *    \c true if successful, else \c false; in this case, check the
+ *    encoder state with FLAC__seekable_stream_encoder_get_state() to see what
+ *    went wrong.
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_process_interleaved(FLAC__SeekableStreamEncoder *encoder, const FLAC__int32 buffer[], unsigned samples);
+
+/* \} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/FLAC/stream_decoder.h
@@ -1,0 +1,873 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__STREAM_DECODER_H
+#define FLAC__STREAM_DECODER_H
+
+#include "export.h"
+#include "format.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** \file include/FLAC/stream_decoder.h
+ *
+ *  \brief
+ *  This module contains the functions which implement the stream
+ *  decoder.
+ *
+ *  See the detailed documentation in the
+ *  \link flac_stream_decoder stream decoder \endlink module.
+ */
+
+/** \defgroup flac_decoder FLAC/ *_decoder.h: decoder interfaces
+ *  \ingroup flac
+ *
+ *  \brief
+ *  This module describes the three decoder layers provided by libFLAC.
+ *
+ * For decoding FLAC streams, libFLAC provides three layers of access.  The
+ * lowest layer is non-seekable stream-level decoding, the next is seekable
+ * stream-level decoding, and the highest layer is file-level decoding.  The
+ * interfaces are described in the \link flac_stream_decoder stream decoder
+ * \endlink, \link flac_seekable_stream_decoder seekable stream decoder
+ * \endlink, and \link flac_file_decoder file decoder \endlink modules
+ * respectively.  Typically you will choose the highest layer that your input
+ * source will support.
+ *
+ * The stream decoder relies on callbacks for all input and output and has no
+ * provisions for seeking.  The seekable stream decoder wraps the stream
+ * decoder and exposes functions for seeking.  However, you must provide
+ * extra callbacks for seek-related operations on your stream, like seek and
+ * tell.  The file decoder wraps the seekable stream decoder and supplies
+ * most of the callbacks internally, simplifying the processing of standard
+ * files.
+ */
+
+/** \defgroup flac_stream_decoder FLAC/stream_decoder.h: stream decoder interface
+ *  \ingroup flac_decoder
+ *
+ *  \brief
+ *  This module contains the functions which implement the stream
+ *  decoder.
+ *
+ * The basic usage of this decoder is as follows:
+ * - The program creates an instance of a decoder using
+ *   FLAC__stream_decoder_new().
+ * - The program overrides the default settings and sets callbacks for
+ *   reading, writing, error reporting, and metadata reporting using
+ *   FLAC__stream_decoder_set_*() functions.
+ * - The program initializes the instance to validate the settings and
+ *   prepare for decoding using FLAC__stream_decoder_init().
+ * - The program calls the FLAC__stream_decoder_process_*() functions
+ *   to decode data, which subsequently calls the callbacks.
+ * - The program finishes the decoding with FLAC__stream_decoder_finish(),
+ *   which flushes the input and output and resets the decoder to the
+ *   uninitialized state.
+ * - The instance may be used again or deleted with
+ *   FLAC__stream_decoder_delete().
+ *
+ * In more detail, the program will create a new instance by calling
+ * FLAC__stream_decoder_new(), then call FLAC__stream_decoder_set_*()
+ * functions to set the callbacks and client data, and call
+ * FLAC__stream_decoder_init().  The required callbacks are:
+ *
+ * - Read callback - This function will be called when the decoder needs
+ *   more input data.  The address of the buffer to be filled is supplied,
+ *   along with the number of bytes the buffer can hold.  The callback may
+ *   choose to supply less data and modify the byte count but must be careful
+ *   not to overflow the buffer.  The callback then returns a status code
+ *   chosen from FLAC__StreamDecoderReadStatus.
+ * - Write callback - This function will be called when the decoder has
+ *   decoded a single frame of data.  The decoder will pass the frame
+ *   metadata as well as an array of pointers (one for each channel)
+ *   pointing to the decoded audio.
+ * - Metadata callback - This function will be called when the decoder has
+ *   decoded a metadata block.  In a valid FLAC file there will always be
+ *   one STREAMINFO block, followed by zero or more other metadata
+ *   blocks.  These will be supplied by the decoder in the same order as
+ *   they appear in the stream and always before the first audio frame
+ *   (i.e. write callback).  The metadata block that is passed in must not
+ *   be modified, and it doesn't live beyond the callback, so you should
+ *   make a copy of it with FLAC__metadata_object_clone() if you will need
+ *   it elsewhere.  Since metadata blocks can potentially be large, by
+ *   default the decoder only calls the metadata callback for the STREAMINFO
+ *   block; you can instruct the decoder to pass or filter other blocks with
+ *   FLAC__stream_decoder_set_metadata_*() calls.
+ * - Error callback - This function will be called whenever an error occurs
+ *   during decoding.
+ *
+ * Once the decoder is initialized, your program will call one of several
+ * functions to start the decoding process:
+ *
+ * - FLAC__stream_decoder_process_single() - Tells the decoder to process at
+ *   most one metadata block or audio frame and return, calling either the
+ *   metadata callback or write callback, respectively, once.  If the decoder
+ *   loses sync it will return with only the error callback being called.
+ * - FLAC__stream_decoder_process_until_end_of_metadata() - Tells the decoder
+ *   to process the stream from the current location and stop upon reaching
+ *   the first audio frame.  The user will get one metadata, write, or error
+ *   callback per metadata block, audio frame, or sync error, respectively.
+ * - FLAC__stream_decoder_process_until_end_of_stream() - Tells the decoder
+ *   to process the stream from the current location until the read callback
+ *   returns FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM or
+ *   FLAC__STREAM_DECODER_READ_STATUS_ABORT.  The user will get one metadata,
+ *   write, or error callback per metadata block, audio frame, or sync error,
+ *   respectively.
+ *
+ * When the decoder has finished decoding (normally or through an abort),
+ * the instance is finished by calling FLAC__stream_decoder_finish(), which
+ * ensures the decoder is in the correct state and frees memory.  Then the
+ * instance may be deleted with FLAC__stream_decoder_delete() or initialized
+ * again to decode another stream.
+ *
+ * Note that the stream decoder has no real concept of stream position, it
+ * just converts data.  To seek within a stream the callbacks have only to
+ * flush the decoder using FLAC__stream_decoder_flush() and start feeding
+ * data from the new position through the read callback.  The seekable
+ * stream decoder does just this.
+ *
+ * The FLAC__stream_decoder_set_metadata_*() functions deserve special
+ * attention.  By default, the decoder only calls the metadata_callback for
+ * the STREAMINFO block.  These functions allow you to tell the decoder
+ * explicitly which blocks to parse and return via the metadata_callback
+ * and/or which to skip.  Use a FLAC__stream_decoder_set_metadata_respond_all(),
+ * FLAC__stream_decoder_set_metadata_ignore() ... or FLAC__stream_decoder_set_metadata_ignore_all(),
+ * FLAC__stream_decoder_set_metadata_respond() ... sequence to exactly specify which
+ * blocks to return.  Remember that some metadata blocks can be big so
+ * filtering out the ones you don't use can reduce the memory requirements
+ * of the decoder.  Also note the special forms
+ * FLAC__stream_decoder_set_metadata_respond_application(id) and
+ * FLAC__stream_decoder_set_metadata_ignore_application(id) for filtering APPLICATION
+ * blocks based on the application ID.
+ *
+ * STREAMINFO and SEEKTABLE blocks are always parsed and used internally, but
+ * they still can legally be filtered from the metadata_callback.
+ *
+ * \note
+ * The "set" functions may only be called when the decoder is in the
+ * state FLAC__STREAM_DECODER_UNINITIALIZED, i.e. after
+ * FLAC__stream_decoder_new() or FLAC__stream_decoder_finish(), but
+ * before FLAC__stream_decoder_init().  If this is the case they will
+ * return \c true, otherwise \c false.
+ *
+ * \note
+ * FLAC__stream_decoder_finish() resets all settings to the constructor
+ * defaults, including the callbacks.
+ *
+ * \{
+ */
+
+
+/** State values for a FLAC__StreamDecoder
+ *
+ *  The decoder's state can be obtained by calling FLAC__stream_decoder_get_state().
+ */
+typedef enum {
+
+	FLAC__STREAM_DECODER_SEARCH_FOR_METADATA = 0,
+	/**< The decoder is ready to search for metadata. */
+
+	FLAC__STREAM_DECODER_READ_METADATA,
+	/**< The decoder is ready to or is in the process of reading metadata. */
+
+	FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC,
+	/**< The decoder is ready to or is in the process of searching for the frame sync code. */
+
+	FLAC__STREAM_DECODER_READ_FRAME,
+	/**< The decoder is ready to or is in the process of reading a frame. */
+
+	FLAC__STREAM_DECODER_END_OF_STREAM,
+	/**< The decoder has reached the end of the stream. */
+
+	FLAC__STREAM_DECODER_ABORTED,
+	/**< The decoder was aborted by the read callback. */
+
+	FLAC__STREAM_DECODER_UNPARSEABLE_STREAM,
+	/**< The decoder encountered reserved fields in use in the stream. */
+
+	FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR,
+	/**< An error occurred allocating memory. */
+
+	FLAC__STREAM_DECODER_ALREADY_INITIALIZED,
+	/**< FLAC__stream_decoder_init() was called when the decoder was
+	 * already initialized, usually because
+	 * FLAC__stream_decoder_finish() was not called.
+	 */
+
+	FLAC__STREAM_DECODER_INVALID_CALLBACK,
+	/**< FLAC__stream_decoder_init() was called without all callbacks being set. */
+
+	FLAC__STREAM_DECODER_UNINITIALIZED
+	/**< The decoder is in the uninitialized state. */
+
+} FLAC__StreamDecoderState;
+
+/** Maps a FLAC__StreamDecoderState to a C string.
+ *
+ *  Using a FLAC__StreamDecoderState as the index to this array
+ *  will give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamDecoderStateString[];
+
+
+/** Return values for the FLAC__StreamDecoder read callback.
+ */
+typedef enum {
+
+	FLAC__STREAM_DECODER_READ_STATUS_CONTINUE,
+	/**< The read was OK and decoding can continue. */
+
+	FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM,
+	/**< The read was attempted at the end of the stream. */
+
+	FLAC__STREAM_DECODER_READ_STATUS_ABORT
+	/**< An unrecoverable error occurred.  The decoder will return from the process call. */
+
+} FLAC__StreamDecoderReadStatus;
+
+/** Maps a FLAC__StreamDecoderReadStatus to a C string.
+ *
+ *  Using a FLAC__StreamDecoderReadStatus as the index to this array
+ *  will give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamDecoderReadStatusString[];
+
+
+/** Return values for the FLAC__StreamDecoder write callback.
+ */
+typedef enum {
+
+	FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE,
+	/**< The write was OK and decoding can continue. */
+
+	FLAC__STREAM_DECODER_WRITE_STATUS_ABORT
+	/**< An unrecoverable error occurred.  The decoder will return from the process call. */
+
+} FLAC__StreamDecoderWriteStatus;
+
+/** Maps a FLAC__StreamDecoderWriteStatus to a C string.
+ *
+ *  Using a FLAC__StreamDecoderWriteStatus as the index to this array
+ *  will give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamDecoderWriteStatusString[];
+
+
+/** Possible values passed in to the FLAC__StreamDecoder error callback.
+ */
+typedef enum {
+
+	FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC,
+	/**< An error in the stream caused the decoder to lose synchronization. */
+
+	FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER,
+	/**< The decoder encountered a corrupted frame header. */
+
+	FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH
+	/**< The frame's data did not match the CRC in the footer. */
+
+} FLAC__StreamDecoderErrorStatus;
+
+/** Maps a FLAC__StreamDecoderErrorStatus to a C string.
+ *
+ *  Using a FLAC__StreamDecoderErrorStatus as the index to this array
+ *  will give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamDecoderErrorStatusString[];
+
+
+/***********************************************************************
+ *
+ * class FLAC__StreamDecoder
+ *
+ ***********************************************************************/
+
+struct FLAC__StreamDecoderProtected;
+struct FLAC__StreamDecoderPrivate;
+/** The opaque structure definition for the stream decoder type.
+ *  See the \link flac_stream_decoder stream decoder module \endlink
+ *  for a detailed description.
+ */
+typedef struct {
+	struct FLAC__StreamDecoderProtected *protected_; /* avoid the C++ keyword 'protected' */
+	struct FLAC__StreamDecoderPrivate *private_; /* avoid the C++ keyword 'private' */
+} FLAC__StreamDecoder;
+
+/** Signature for the read callback.
+ *  See FLAC__stream_decoder_set_read_callback() for more info.
+ *
+ * \param  decoder  The decoder instance calling the callback.
+ * \param  buffer   A pointer to a location for the callee to store
+ *                  data to be decoded.
+ * \param  bytes    A pointer to the size of the buffer.  On entry
+ *                  to the callback, it contains the maximum number
+ *                  of bytes that may be stored in \a buffer.  The
+ *                  callee must set it to the actual number of bytes
+ *                  stored (0 in case of error or end-of-stream) before
+ *                  returning.
+ * \param  client_data  The callee's client data set through
+ *                      FLAC__stream_decoder_set_client_data().
+ * \retval FLAC__StreamDecoderReadStatus
+ *    The callee's return status.
+ */
+typedef FLAC__StreamDecoderReadStatus (*FLAC__StreamDecoderReadCallback)(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data);
+
+/** Signature for the write callback.
+ *  See FLAC__stream_decoder_set_write_callback() for more info.
+ *
+ * \param  decoder  The decoder instance calling the callback.
+ * \param  frame    The description of the decoded frame.  See
+ *                  FLAC__Frame.
+ * \param  buffer   An array of pointers to decoded channels of data.
+ *                  Each pointer will point to an array of signed
+ *                  samples of length \a frame->header.blocksize.
+ *                  Currently, the channel order has no meaning
+ *                  except for stereo streams; in this case channel
+ *                  0 is left and 1 is right.
+ * \param  client_data  The callee's client data set through
+ *                      FLAC__stream_decoder_set_client_data().
+ * \retval FLAC__StreamDecoderWriteStatus
+ *    The callee's return status.
+ */
+typedef FLAC__StreamDecoderWriteStatus (*FLAC__StreamDecoderWriteCallback)(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data);
+
+/** Signature for the metadata callback.
+ *  See FLAC__stream_decoder_set_metadata_callback() for more info.
+ *
+ * \param  decoder  The decoder instance calling the callback.
+ * \param  metadata The decoded metadata block.
+ * \param  client_data  The callee's client data set through
+ *                      FLAC__stream_decoder_set_client_data().
+ */
+typedef void (*FLAC__StreamDecoderMetadataCallback)(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data);
+
+/** Signature for the error callback.
+ *  See FLAC__stream_decoder_set_error_callback() for more info.
+ *
+ * \param  decoder  The decoder instance calling the callback.
+ * \param  status   The error encountered by the decoder.
+ * \param  client_data  The callee's client data set through
+ *                      FLAC__stream_decoder_set_client_data().
+ */
+typedef void (*FLAC__StreamDecoderErrorCallback)(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
+
+
+/***********************************************************************
+ *
+ * Class constructor/destructor
+ *
+ ***********************************************************************/
+
+/** Create a new stream decoder instance.  The instance is created with
+ *  default settings; see the individual FLAC__stream_decoder_set_*()
+ *  functions for each setting's default.
+ *
+ * \retval FLAC__StreamDecoder*
+ *    \c NULL if there was an error allocating memory, else the new instance.
+ */
+FLAC_API FLAC__StreamDecoder *FLAC__stream_decoder_new();
+
+/** Free a decoder instance.  Deletes the object pointed to by \a decoder.
+ *
+ * \param decoder  A pointer to an existing decoder.
+ * \assert
+ *    \code decoder != NULL \endcode
+ */
+FLAC_API void FLAC__stream_decoder_delete(FLAC__StreamDecoder *decoder);
+
+
+/***********************************************************************
+ *
+ * Public class method prototypes
+ *
+ ***********************************************************************/
+
+/** Set the read callback.
+ *  The supplied function will be called when the decoder needs more input
+ *  data.  The address of the buffer to be filled is supplied, along with
+ *  the number of bytes the buffer can hold.  The callback may choose to
+ *  supply less data and modify the byte count but must be careful not to
+ *  overflow the buffer.  The callback then returns a status code chosen
+ *  from FLAC__StreamDecoderReadStatus.
+ *
+ * \note
+ * The callback is mandatory and must be set before initialization.
+ *
+ * \default \c NULL
+ * \param  decoder  A decoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code decoder != NULL \endcode
+ *    \code value != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_set_read_callback(FLAC__StreamDecoder *decoder, FLAC__StreamDecoderReadCallback value);
+
+/** Set the write callback.
+ *  The supplied function will be called when the decoder has decoded a
+ *  single frame of data.  The decoder will pass the frame metadata as
+ *  well as an array of pointers (one for each channel) pointing to the
+ *  decoded audio.
+ *
+ * \note
+ * The callback is mandatory and must be set before initialization.
+ *
+ * \default \c NULL
+ * \param  decoder  A decoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code decoder != NULL \endcode
+ *    \code value != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_set_write_callback(FLAC__StreamDecoder *decoder, FLAC__StreamDecoderWriteCallback value);
+
+/** Set the metadata callback.
+ *  The supplied function will be called when the decoder has decoded a metadata
+ *  block.  In a valid FLAC file there will always be one STREAMINFO block,
+ *  followed by zero or more other metadata blocks.  These will be supplied
+ *  by the decoder in the same order as they appear in the stream and always
+ *  before the first audio frame (i.e. write callback).  The metadata block
+ *  that is passed in must not be modified, and it doesn't live beyond the
+ *  callback, so you should make a copy of it with
+ *  FLAC__metadata_object_clone() if you will need it elsewhere.  Since
+ *  metadata blocks can potentially be large, by default the decoder only
+ *  calls the metadata callback for the STREAMINFO block; you can instruct
+ *  the decoder to pass or filter other blocks with
+ *  FLAC__stream_decoder_set_metadata_*() calls.
+ *
+ * \note
+ * The callback is mandatory and must be set before initialization.
+ *
+ * \default \c NULL
+ * \param  decoder  A decoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code decoder != NULL \endcode
+ *    \code value != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_callback(FLAC__StreamDecoder *decoder, FLAC__StreamDecoderMetadataCallback value);
+
+/** Set the error callback.
+ *  The supplied function will be called whenever an error occurs during
+ *  decoding.
+ *
+ * \note
+ * The callback is mandatory and must be set before initialization.
+ *
+ * \default \c NULL
+ * \param  decoder  A decoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code decoder != NULL \endcode
+ *    \code value != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_set_error_callback(FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorCallback value);
+
+/** Set the client data to be passed back to callbacks.
+ *  This value will be supplied to callbacks in their \a client_data
+ *  argument.
+ *
+ * \default \c NULL
+ * \param  decoder  A decoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_set_client_data(FLAC__StreamDecoder *decoder, void *value);
+
+/** Direct the decoder to pass on all metadata blocks of type \a type.
+ *
+ * \default By default, only the \c STREAMINFO block is returned via the
+ *          metadata callback.
+ * \param  decoder  A decoder instance to set.
+ * \param  type     See above.
+ * \assert
+ *    \code decoder != NULL \endcode
+ *    \a type is valid
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond(FLAC__StreamDecoder *decoder, FLAC__MetadataType type);
+
+/** Direct the decoder to pass on all APPLICATION metadata blocks of the
+ *  given \a id.
+ *
+ * \default By default, only the \c STREAMINFO block is returned via the
+ *          metadata callback.
+ * \param  decoder  A decoder instance to set.
+ * \param  id       See above.
+ * \assert
+ *    \code decoder != NULL \endcode
+ *    \code id != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond_application(FLAC__StreamDecoder *decoder, const FLAC__byte id[4]);
+
+/** Direct the decoder to pass on all metadata blocks of any type.
+ *
+ * \default By default, only the \c STREAMINFO block is returned via the
+ *          metadata callback.
+ * \param  decoder  A decoder instance to set.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond_all(FLAC__StreamDecoder *decoder);
+
+/** Direct the decoder to filter out all metadata blocks of type \a type.
+ *
+ * \default By default, only the \c STREAMINFO block is returned via the
+ *          metadata callback.
+ * \param  decoder  A decoder instance to set.
+ * \param  type     See above.
+ * \assert
+ *    \code decoder != NULL \endcode
+ *    \a type is valid
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore(FLAC__StreamDecoder *decoder, FLAC__MetadataType type);
+
+/** Direct the decoder to filter out all APPLICATION metadata blocks of
+ *  the given \a id.
+ *
+ * \default By default, only the \c STREAMINFO block is returned via the
+ *          metadata callback.
+ * \param  decoder  A decoder instance to set.
+ * \param  id       See above.
+ * \assert
+ *    \code decoder != NULL \endcode
+ *    \code id != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore_application(FLAC__StreamDecoder *decoder, const FLAC__byte id[4]);
+
+/** Direct the decoder to filter out all metadata blocks of any type.
+ *
+ * \default By default, only the \c STREAMINFO block is returned via the
+ *          metadata callback.
+ * \param  decoder  A decoder instance to set.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore_all(FLAC__StreamDecoder *decoder);
+
+/** Get the current decoder state.
+ *
+ * \param  decoder  A decoder instance to query.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__StreamDecoderState
+ *    The current decoder state.
+ */
+FLAC_API FLAC__StreamDecoderState FLAC__stream_decoder_get_state(const FLAC__StreamDecoder *decoder);
+
+/** Get the current decoder state as a C string.
+ *
+ * \param  decoder  A decoder instance to query.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval const char *
+ *    The decoder state as a C string.  Do not modify the contents.
+ */
+FLAC_API const char *FLAC__stream_decoder_get_resolved_state_string(const FLAC__StreamDecoder *decoder);
+
+/** Get the current number of channels in the stream being decoded.
+ *  Will only be valid after decoding has started and will contain the
+ *  value from the most recently decoded frame header.
+ *
+ * \param  decoder  A decoder instance to query.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval unsigned
+ *    See above.
+ */
+FLAC_API unsigned FLAC__stream_decoder_get_channels(const FLAC__StreamDecoder *decoder);
+
+/** Get the current channel assignment in the stream being decoded.
+ *  Will only be valid after decoding has started and will contain the
+ *  value from the most recently decoded frame header.
+ *
+ * \param  decoder  A decoder instance to query.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__ChannelAssignment
+ *    See above.
+ */
+FLAC_API FLAC__ChannelAssignment FLAC__stream_decoder_get_channel_assignment(const FLAC__StreamDecoder *decoder);
+
+/** Get the current sample resolution in the stream being decoded.
+ *  Will only be valid after decoding has started and will contain the
+ *  value from the most recently decoded frame header.
+ *
+ * \param  decoder  A decoder instance to query.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval unsigned
+ *    See above.
+ */
+FLAC_API unsigned FLAC__stream_decoder_get_bits_per_sample(const FLAC__StreamDecoder *decoder);
+
+/** Get the current sample rate in Hz of the stream being decoded.
+ *  Will only be valid after decoding has started and will contain the
+ *  value from the most recently decoded frame header.
+ *
+ * \param  decoder  A decoder instance to query.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval unsigned
+ *    See above.
+ */
+FLAC_API unsigned FLAC__stream_decoder_get_sample_rate(const FLAC__StreamDecoder *decoder);
+
+/** Get the current blocksize of the stream being decoded.
+ *  Will only be valid after decoding has started and will contain the
+ *  value from the most recently decoded frame header.
+ *
+ * \param  decoder  A decoder instance to query.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval unsigned
+ *    See above.
+ */
+FLAC_API unsigned FLAC__stream_decoder_get_blocksize(const FLAC__StreamDecoder *decoder);
+
+/** Initialize the decoder instance.
+ *  Should be called after FLAC__stream_decoder_new() and
+ *  FLAC__stream_decoder_set_*() but before any of the
+ *  FLAC__stream_decoder_process_*() functions.  Will set and return the
+ *  decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA
+ *  if initialization succeeded.
+ *
+ * \param  decoder  An uninitialized decoder instance.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__StreamDecoderState
+ *    \c FLAC__STREAM_DECODER_SEARCH_FOR_METADATA if initialization was
+ *    successful; see FLAC__StreamDecoderState for the meanings of other
+ *    return values.
+ */
+FLAC_API FLAC__StreamDecoderState FLAC__stream_decoder_init(FLAC__StreamDecoder *decoder);
+
+/** Finish the decoding process.
+ *  Flushes the decoding buffer, releases resources, resets the decoder
+ *  settings to their defaults, and returns the decoder state to
+ *  FLAC__STREAM_DECODER_UNINITIALIZED.
+ *
+ *  In the event of a prematurely-terminated decode, it is not strictly
+ *  necessary to call this immediately before FLAC__stream_decoder_delete()
+ *  but it is good practice to match every FLAC__stream_decoder_init()
+ *  with a FLAC__stream_decoder_finish().
+ *
+ * \param  decoder  An uninitialized decoder instance.
+ * \assert
+ *    \code decoder != NULL \endcode
+ */
+FLAC_API void FLAC__stream_decoder_finish(FLAC__StreamDecoder *decoder);
+
+/** Flush the stream input.
+ *  The decoder's input buffer will be cleared and the state set to
+ *  \c FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC.
+ *
+ * \param  decoder  A decoder instance.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if successful, else \c false if a memory allocation
+ *    error occurs.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_flush(FLAC__StreamDecoder *decoder);
+
+/** Reset the decoding process.
+ *  The decoder's input buffer will be cleared and the state set to
+ *  \c FLAC__STREAM_DECODER_SEARCH_FOR_METADATA.  This is similar to
+ *  FLAC__stream_decoder_finish() except that the settings are
+ *  preserved; there is no need to call FLAC__stream_decoder_init()
+ *  before decoding again.
+ *
+ * \param  decoder  A decoder instance.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if successful, else \c false if a memory allocation
+ *    error occurs.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_reset(FLAC__StreamDecoder *decoder);
+
+/** Decode one metadata block or audio frame.
+ *  This version instructs the decoder to decode a either a single metadata
+ *  block or a single frame and stop, unless the callbacks return a fatal
+ *  error or the read callback returns
+ *  \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM.
+ *
+ *  As the decoder needs more input it will call the read callback.
+ *  Depending on what was decoded, the metadata or write callback will be
+ *  called with the decoded metadata block or audio frame, unless an error
+ *  occurred.  If the decoder loses sync it will call the error callback
+ *  instead.
+ *
+ *  Unless there is a fatal read error or end of stream, this function
+ *  will return once one whole frame is decoded.  In other words, if the
+ *  stream is not synchronized or points to a corrupt frame header, the
+ *  decoder will continue to try and resync until it gets to a valid
+ *  frame, then decode one frame, then return.  If the decoder points to
+ *  frame whose frame CRC in the frame footer does not match the
+ *  computed frame CRC, this function will issue a
+ *  FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH error to the
+ *  error callback, and return, having decoded one complete, although
+ *  corrupt, frame.  (Such corrupted frames are sent as silence of the
+ *  correct length to the write callback.)
+ *
+ * \param  decoder  An initialized decoder instance.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if any read or write error occurred (except
+ *    \c FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC), else \c true;
+ *    in any case, check the decoder state with
+ *    FLAC__stream_decoder_get_state() to see what went wrong or to
+ *    check for lost synchronization (a sign of stream corruption).
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_process_single(FLAC__StreamDecoder *decoder);
+
+/** Decode until the end of the metadata.
+ *  This version instructs the decoder to decode from the current position
+ *  and continue until all the metadata has been read, or until the
+ *  callbacks return a fatal error or the read callback returns
+ *  \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM.
+ *
+ *  As the decoder needs more input it will call the read callback.
+ *  As each metadata block is decoded, the metadata callback will be called
+ *  with the decoded metadata.  If the decoder loses sync it will call the
+ *  error callback.
+ *
+ * \param  decoder  An initialized decoder instance.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if any read or write error occurred (except
+ *    \c FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC), else \c true;
+ *    in any case, check the decoder state with
+ *    FLAC__stream_decoder_get_state() to see what went wrong or to
+ *    check for lost synchronization (a sign of stream corruption).
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_metadata(FLAC__StreamDecoder *decoder);
+
+/** Decode until the end of the stream.
+ *  This version instructs the decoder to decode from the current position
+ *  and continue until the end of stream (the read callback returns
+ *  \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM), or until the
+ *  callbacks return a fatal error.
+ *
+ *  As the decoder needs more input it will call the read callback.
+ *  As each metadata block and frame is decoded, the metadata or write
+ *  callback will be called with the decoded metadata or frame.  If the
+ *  decoder loses sync it will call the error callback.
+ *
+ * \param  decoder  An initialized decoder instance.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if any read or write error occurred (except
+ *    \c FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC), else \c true;
+ *    in any case, check the decoder state with
+ *    FLAC__stream_decoder_get_state() to see what went wrong or to
+ *    check for lost synchronization (a sign of stream corruption).
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_stream(FLAC__StreamDecoder *decoder);
+
+/** Skip one audio frame.
+ *  This version instructs the decoder to 'skip' a single frame and stop,
+ *  unless the callbacks return a fatal error or the read callback returns
+ *  \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM.
+ *
+ *  The decoding flow is the same as what occurs when
+ *  FLAC__stream_decoder_process_single() is called to process an audio
+ *  frame, except that this function does not decode the parsed data into
+ *  PCM or call the write callback.  The integrity of the frame is still
+ *  checked the same way as in the other process functions.
+ *
+ *  This function will return once one whole frame is skipped, in the
+ *  same way that FLAC__stream_decoder_process_single() will return once
+ *  one whole frame is decoded.
+ *
+ *  This function, when used from the higher FLAC__SeekableStreamDecoder
+ *  layer, can be used in more quickly determining FLAC frame boundaries
+ *  when decoding of the actual data is not needed, for example when a
+ *  application is separating a FLAC stream into frames for editing or
+ *  storing in a container.  To do this, the application can use
+ *  FLAC__seekable_stream_decoder_skip_single_frame() to quickly advance
+ *  to the next frame, then use
+ *  FLAC__seekable_stream_decoder_get_decode_position() to find the new
+ *  frame boundary.
+ *
+ *  This function should only be called when the stream has advanced
+ *  past all the metadata, otherwise it will return \c false.
+ *
+ * \param  decoder  An initialized decoder instance not in a metadata
+ *                  state.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if any read or write error occurred (except
+ *    \c FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC), or if the decoder
+ *    is in the FLAC__STREAM_DECODER_SEARCH_FOR_METADATA or
+ *    FLAC__STREAM_DECODER_READ_METADATA state, else \c true;
+ *    in any case, check the decoder state with
+ *    FLAC__stream_decoder_get_state() to see what went wrong or to
+ *    check for lost synchronization (a sign of stream corruption).
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_skip_single_frame(FLAC__StreamDecoder *decoder);
+
+/* \} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/FLAC/stream_encoder.h
@@ -1,0 +1,1064 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__STREAM_ENCODER_H
+#define FLAC__STREAM_ENCODER_H
+
+#include "export.h"
+#include "format.h"
+#include "stream_decoder.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** \file include/FLAC/stream_encoder.h
+ *
+ *  \brief
+ *  This module contains the functions which implement the stream
+ *  encoder.
+ *
+ *  See the detailed documentation in the
+ *  \link flac_stream_encoder stream encoder \endlink module.
+ */
+
+/** \defgroup flac_encoder FLAC/ *_encoder.h: encoder interfaces
+ *  \ingroup flac
+ *
+ *  \brief
+ *  This module describes the two encoder layers provided by libFLAC.
+ *
+ * For encoding FLAC streams, libFLAC provides three layers of access.  The
+ * lowest layer is non-seekable stream-level encoding, the next is seekable
+ * stream-level encoding, and the highest layer is file-level encoding.  The
+ * interfaces are described in the \link flac_stream_encoder stream encoder
+ * \endlink, \link flac_seekable_stream_encoder seekable stream encoder
+ * \endlink, and \link flac_file_encoder file encoder \endlink modules
+ * respectively.  Typically you will choose the highest layer that your input
+ * source will support.
+ * The stream encoder relies on callbacks for writing the data and
+ * metadata. The file encoder provides these callbacks internally and you
+ * need only supply the filename.
+ *
+ * The stream encoder relies on callbacks for writing the data and has no
+ * provisions for seeking the output.  The seekable stream encoder wraps
+ * the stream encoder and also automaticallay handles the writing back of
+ * metadata discovered while encoding.  However, you must provide extra
+ * callbacks for seek-related operations on your output, like seek and
+ * tell.  The file encoder wraps the seekable stream encoder and supplies
+ * all of the callbacks internally, simplifying the processing of standard
+ * files.  The only callback exposed is for progress reporting, and that
+ * is optional.
+ */
+
+/** \defgroup flac_stream_encoder FLAC/stream_encoder.h: stream encoder interface
+ *  \ingroup flac_encoder
+ *
+ *  \brief
+ *  This module contains the functions which implement the stream
+ *  encoder.
+ *
+ * The basic usage of this encoder is as follows:
+ * - The program creates an instance of an encoder using
+ *   FLAC__stream_encoder_new().
+ * - The program overrides the default settings and sets callbacks using
+ *   FLAC__stream_encoder_set_*() functions.
+ * - The program initializes the instance to validate the settings and
+ *   prepare for encoding using FLAC__stream_encoder_init().
+ * - The program calls FLAC__stream_encoder_process() or
+ *   FLAC__stream_encoder_process_interleaved() to encode data, which
+ *   subsequently calls the callbacks when there is encoder data ready
+ *   to be written.
+ * - The program finishes the encoding with FLAC__stream_encoder_finish(),
+ *   which causes the encoder to encode any data still in its input pipe,
+ *   call the metadata callback with the final encoding statistics, and
+ *   finally reset the encoder to the uninitialized state.
+ * - The instance may be used again or deleted with
+ *   FLAC__stream_encoder_delete().
+ *
+ * In more detail, the stream encoder functions similarly to the
+ * \link flac_stream_decoder stream decoder \endlink, but has fewer
+ * callbacks and more options.  Typically the user will create a new
+ * instance by calling FLAC__stream_encoder_new(), then set the necessary
+ * parameters and callbacks with FLAC__stream_encoder_set_*(), and
+ * initialize it by calling FLAC__stream_encoder_init().
+ *
+ * Unlike the decoders, the stream encoder has many options that can
+ * affect the speed and compression ratio.  When setting these parameters
+ * you should have some basic knowledge of the format (see the
+ * <A HREF="../documentation.html#format">user-level documentation</A>
+ * or the <A HREF="../format.html">formal description</A>).  The
+ * FLAC__stream_encoder_set_*() functions themselves do not validate the
+ * values as many are interdependent.  The FLAC__stream_encoder_init()
+ * function will do this, so make sure to pay attention to the state
+ * returned by FLAC__stream_encoder_init() to make sure that it is
+ * FLAC__STREAM_ENCODER_OK.  Any parameters that are not set before
+ * FLAC__stream_encoder_init() will take on the defaults from the
+ * constructor.
+ *
+ * The user must provide function pointers for the following callbacks:
+ *
+ * - Write callback - This function is called by the encoder anytime there
+ *   is raw encoded data to write.  It may include metadata mixed with
+ *   encoded audio frames and the data is not guaranteed to be aligned on
+ *   frame or metadata block boundaries.
+ * - Metadata callback - This function is called once at the end of
+ *   encoding with the populated STREAMINFO structure.  This is so file
+ *   encoders can seek back to the beginning of the file and write the
+ *   STREAMINFO block with the correct statistics after encoding (like
+ *   minimum/maximum frame size).
+ *
+ * The call to FLAC__stream_encoder_init() currently will also immediately
+ * call the write callback several times, once with the \c fLaC signature,
+ * and once for each encoded metadata block.
+ *
+ * After initializing the instance, the user may feed audio data to the
+ * encoder in one of two ways:
+ *
+ * - Channel separate, through FLAC__stream_encoder_process() - The user
+ *   will pass an array of pointers to buffers, one for each channel, to
+ *   the encoder, each of the same length.  The samples need not be
+ *   block-aligned.
+ * - Channel interleaved, through
+ *   FLAC__stream_encoder_process_interleaved() - The user will pass a single
+ *   pointer to data that is channel-interleaved (i.e. channel0_sample0,
+ *   channel1_sample0, ... , channelN_sample0, channel0_sample1, ...).
+ *   Again, the samples need not be block-aligned but they must be
+ *   sample-aligned, i.e. the first value should be channel0_sample0 and
+ *   the last value channelN_sampleM.
+ *
+ * When the user is finished encoding data, it calls
+ * FLAC__stream_encoder_finish(), which causes the encoder to encode any
+ * data still in its input pipe, and call the metadata callback with the
+ * final encoding statistics.  Then the instance may be deleted with
+ * FLAC__stream_encoder_delete() or initialized again to encode another
+ * stream.
+ *
+ * For programs that write their own metadata, but that do not know the
+ * actual metadata until after encoding, it is advantageous to instruct
+ * the encoder to write a PADDING block of the correct size, so that
+ * instead of rewriting the whole stream after encoding, the program can
+ * just overwrite the PADDING block.  If only the maximum size of the
+ * metadata is known, the program can write a slightly larger padding
+ * block, then split it after encoding.
+ *
+ * Make sure you understand how lengths are calculated.  All FLAC metadata
+ * blocks have a 4 byte header which contains the type and length.  This
+ * length does not include the 4 bytes of the header.  See the format page
+ * for the specification of metadata blocks and their lengths.
+ *
+ * \note
+ * The "set" functions may only be called when the encoder is in the
+ * state FLAC__STREAM_ENCODER_UNINITIALIZED, i.e. after
+ * FLAC__stream_encoder_new() or FLAC__stream_encoder_finish(), but
+ * before FLAC__stream_encoder_init().  If this is the case they will
+ * return \c true, otherwise \c false.
+ *
+ * \note
+ * FLAC__stream_encoder_finish() resets all settings to the constructor
+ * defaults, including the callbacks.
+ *
+ * \{
+ */
+
+
+/** State values for a FLAC__StreamEncoder
+ *
+ *  The encoder's state can be obtained by calling FLAC__stream_encoder_get_state().
+ */
+typedef enum {
+
+	FLAC__STREAM_ENCODER_OK = 0,
+	/**< The encoder is in the normal OK state. */
+
+	FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR,
+	/**< An error occurred in the underlying verify stream decoder;
+	 * check FLAC__stream_encoder_get_verify_decoder_state().
+	 */
+
+	FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA,
+	/**< The verify decoder detected a mismatch between the original
+	 * audio signal and the decoded audio signal.
+	 */
+
+	FLAC__STREAM_ENCODER_INVALID_CALLBACK,
+	/**< The encoder was initialized before setting all the required callbacks. */
+
+	FLAC__STREAM_ENCODER_INVALID_NUMBER_OF_CHANNELS,
+	/**< The encoder has an invalid setting for number of channels. */
+
+	FLAC__STREAM_ENCODER_INVALID_BITS_PER_SAMPLE,
+	/**< The encoder has an invalid setting for bits-per-sample.
+	 * FLAC supports 4-32 bps but the reference encoder currently supports
+	 * only up to 24 bps.
+	 */
+
+	FLAC__STREAM_ENCODER_INVALID_SAMPLE_RATE,
+	/**< The encoder has an invalid setting for the input sample rate. */
+
+	FLAC__STREAM_ENCODER_INVALID_BLOCK_SIZE,
+	/**< The encoder has an invalid setting for the block size. */
+
+	FLAC__STREAM_ENCODER_INVALID_MAX_LPC_ORDER,
+	/**< The encoder has an invalid setting for the maximum LPC order. */
+
+	FLAC__STREAM_ENCODER_INVALID_QLP_COEFF_PRECISION,
+	/**< The encoder has an invalid setting for the precision of the quantized linear predictor coefficients. */
+
+	FLAC__STREAM_ENCODER_MID_SIDE_CHANNELS_MISMATCH,
+	/**< Mid/side coding was specified but the number of channels is not equal to 2. */
+
+	FLAC__STREAM_ENCODER_MID_SIDE_SAMPLE_SIZE_MISMATCH,
+	/**< Deprecated. */
+
+	FLAC__STREAM_ENCODER_ILLEGAL_MID_SIDE_FORCE,
+	/**< Loose mid/side coding was specified but mid/side coding was not. */
+
+	FLAC__STREAM_ENCODER_BLOCK_SIZE_TOO_SMALL_FOR_LPC_ORDER,
+	/**< The specified block size is less than the maximum LPC order. */
+
+	FLAC__STREAM_ENCODER_NOT_STREAMABLE,
+	/**< The encoder is bound to the "streamable subset" but other settings violate it. */
+
+	FLAC__STREAM_ENCODER_FRAMING_ERROR,
+	/**< An error occurred while writing the stream; usually, the write_callback returned an error. */
+
+	FLAC__STREAM_ENCODER_INVALID_METADATA,
+	/**< The metadata input to the encoder is invalid, in one of the following ways:
+	 * - FLAC__stream_encoder_set_metadata() was called with a null pointer but a block count > 0
+	 * - One of the metadata blocks contains an undefined type
+	 * - It contains an illegal CUESHEET as checked by FLAC__format_cuesheet_is_legal()
+	 * - It contains an illegal SEEKTABLE as checked by FLAC__format_seektable_is_legal()
+	 * - It contains more than one SEEKTABLE block or more than one VORBIS_COMMENT block
+	 */
+
+	FLAC__STREAM_ENCODER_FATAL_ERROR_WHILE_ENCODING,
+	/**< An error occurred while writing the stream; usually, the write_callback returned an error. */
+
+	FLAC__STREAM_ENCODER_FATAL_ERROR_WHILE_WRITING,
+	/**< The write_callback returned an error. */
+
+	FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR,
+	/**< Memory allocation failed. */
+
+	FLAC__STREAM_ENCODER_ALREADY_INITIALIZED,
+	/**< FLAC__stream_encoder_init() was called when the encoder was
+	 * already initialized, usually because
+	 * FLAC__stream_encoder_finish() was not called.
+	 */
+
+	FLAC__STREAM_ENCODER_UNINITIALIZED
+	/**< The encoder is in the uninitialized state. */
+
+} FLAC__StreamEncoderState;
+
+/** Maps a FLAC__StreamEncoderState to a C string.
+ *
+ *  Using a FLAC__StreamEncoderState as the index to this array
+ *  will give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamEncoderStateString[];
+
+/** Return values for the FLAC__StreamEncoder write callback.
+ */
+typedef enum {
+
+	FLAC__STREAM_ENCODER_WRITE_STATUS_OK = 0,
+	/**< The write was OK and encoding can continue. */
+
+	FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR
+	/**< An unrecoverable error occurred.  The encoder will return from the process call. */
+
+} FLAC__StreamEncoderWriteStatus;
+
+/** Maps a FLAC__StreamEncoderWriteStatus to a C string.
+ *
+ *  Using a FLAC__StreamEncoderWriteStatus as the index to this array
+ *  will give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamEncoderWriteStatusString[];
+
+
+/***********************************************************************
+ *
+ * class FLAC__StreamEncoder
+ *
+ ***********************************************************************/
+
+struct FLAC__StreamEncoderProtected;
+struct FLAC__StreamEncoderPrivate;
+/** The opaque structure definition for the stream encoder type.
+ *  See the \link flac_stream_encoder stream encoder module \endlink
+ *  for a detailed description.
+ */
+typedef struct {
+	struct FLAC__StreamEncoderProtected *protected_; /* avoid the C++ keyword 'protected' */
+	struct FLAC__StreamEncoderPrivate *private_; /* avoid the C++ keyword 'private' */
+} FLAC__StreamEncoder;
+
+/** Signature for the write callback.
+ *  See FLAC__stream_encoder_set_write_callback() for more info.
+ *
+ * \param  encoder  The encoder instance calling the callback.
+ * \param  buffer   An array of encoded data of length \a bytes.
+ * \param  bytes    The byte length of \a buffer.
+ * \param  samples  The number of samples encoded by \a buffer.
+ *                  \c 0 has a special meaning; see
+ *                  FLAC__stream_encoder_set_write_callback().
+ * \param  current_frame  The number of the current frame being encoded.
+ * \param  client_data  The callee's client data set through
+ *                      FLAC__stream_encoder_set_client_data().
+ * \retval FLAC__StreamEncoderWriteStatus
+ *    The callee's return status.
+ */
+typedef FLAC__StreamEncoderWriteStatus (*FLAC__StreamEncoderWriteCallback)(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data);
+
+/** Signature for the metadata callback.
+ *  See FLAC__stream_encoder_set_metadata_callback() for more info.
+ *
+ * \param  encoder      The encoder instance calling the callback.
+ * \param  metadata     The final populated STREAMINFO block.
+ * \param  client_data  The callee's client data set through
+ *                      FLAC__stream_encoder_set_client_data().
+ */
+typedef void (*FLAC__StreamEncoderMetadataCallback)(const FLAC__StreamEncoder *encoder, const FLAC__StreamMetadata *metadata, void *client_data);
+
+
+/***********************************************************************
+ *
+ * Class constructor/destructor
+ *
+ ***********************************************************************/
+
+/** Create a new stream encoder instance.  The instance is created with
+ *  default settings; see the individual FLAC__stream_encoder_set_*()
+ *  functions for each setting's default.
+ *
+ * \retval FLAC__StreamEncoder*
+ *    \c NULL if there was an error allocating memory, else the new instance.
+ */
+FLAC_API FLAC__StreamEncoder *FLAC__stream_encoder_new();
+
+/** Free an encoder instance.  Deletes the object pointed to by \a encoder.
+ *
+ * \param encoder  A pointer to an existing encoder.
+ * \assert
+ *    \code encoder != NULL \endcode
+ */
+FLAC_API void FLAC__stream_encoder_delete(FLAC__StreamEncoder *encoder);
+
+
+/***********************************************************************
+ *
+ * Public class method prototypes
+ *
+ ***********************************************************************/
+
+/** Set the "verify" flag.  If \c true, the encoder will verify it's own
+ *  encoded output by feeding it through an internal decoder and comparing
+ *  the original signal against the decoded signal.  If a mismatch occurs,
+ *  the process call will return \c false.  Note that this will slow the
+ *  encoding process by the extra time required for decoding and comparison.
+ *
+ * \default \c false
+ * \param  encoder  An encoder instance to set.
+ * \param  value    Flag value (see above).
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_verify(FLAC__StreamEncoder *encoder, FLAC__bool value);
+
+/** Set the "streamable subset" flag.  If \c true, the encoder will comply
+ *  with the subset (see the format specification) and will check the
+ *  settings during FLAC__stream_encoder_init() to see if all settings
+ *  comply.  If \c false, the settings may take advantage of the full
+ *  range that the format allows.
+ *
+ *  Make sure you know what it entails before setting this to \c false.
+ *
+ * \default \c true
+ * \param  encoder  An encoder instance to set.
+ * \param  value    Flag value (see above).
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_streamable_subset(FLAC__StreamEncoder *encoder, FLAC__bool value);
+
+/** Set to \c true to enable mid-side encoding on stereo input.  The
+ *  number of channels must be 2.  Set to \c false to use only
+ *  independent channel coding.
+ *
+ * \default \c false
+ * \param  encoder  An encoder instance to set.
+ * \param  value    Flag value (see above).
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_do_mid_side_stereo(FLAC__StreamEncoder *encoder, FLAC__bool value);
+
+/** Set to \c true to enable adaptive switching between mid-side and
+ *  left-right encoding on stereo input.  The number of channels must
+ *  be 2.  Set to \c false to use exhaustive searching.  In either
+ *  case, the mid/side stereo setting must be \c true.
+ *
+ * \default \c false
+ * \param  encoder  An encoder instance to set.
+ * \param  value    Flag value (see above).
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_loose_mid_side_stereo(FLAC__StreamEncoder *encoder, FLAC__bool value);
+
+/** Set the number of channels to be encoded.
+ *
+ * \default \c 2
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_channels(FLAC__StreamEncoder *encoder, unsigned value);
+
+/** Set the sample resolution of the input to be encoded.
+ *
+ * \warning
+ * Do not feed the encoder data that is wider than the value you
+ * set here or you will generate an invalid stream.
+ *
+ * \default \c 16
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_bits_per_sample(FLAC__StreamEncoder *encoder, unsigned value);
+
+/** Set the sample rate (in Hz) of the input to be encoded.
+ *
+ * \default \c 44100
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_sample_rate(FLAC__StreamEncoder *encoder, unsigned value);
+
+/** Set the blocksize to use while encoding.
+ *
+ * \default \c 1152
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_blocksize(FLAC__StreamEncoder *encoder, unsigned value);
+
+/** Set the maximum LPC order, or \c 0 to use only the fixed predictors.
+ *
+ * \default \c 0
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_max_lpc_order(FLAC__StreamEncoder *encoder, unsigned value);
+
+/** Set the precision, in bits, of the quantized linear predictor
+ *  coefficients, or \c 0 to let the encoder select it based on the
+ *  blocksize.
+ *
+ * \note
+ * In the current implementation, qlp_coeff_precision + bits_per_sample must
+ * be less than 32.
+ *
+ * \default \c 0
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_qlp_coeff_precision(FLAC__StreamEncoder *encoder, unsigned value);
+
+/** Set to \c false to use only the specified quantized linear predictor
+ *  coefficient precision, or \c true to search neighboring precision
+ *  values and use the best one.
+ *
+ * \default \c false
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_do_qlp_coeff_prec_search(FLAC__StreamEncoder *encoder, FLAC__bool value);
+
+/** Deprecated.  Setting this value has no effect.
+ *
+ * \default \c false
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_do_escape_coding(FLAC__StreamEncoder *encoder, FLAC__bool value);
+
+/** Set to \c false to let the encoder estimate the best model order
+ *  based on the residual signal energy, or \c true to force the
+ *  encoder to evaluate all order models and select the best.
+ *
+ * \default \c false
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_do_exhaustive_model_search(FLAC__StreamEncoder *encoder, FLAC__bool value);
+
+/** Set the minimum partition order to search when coding the residual.
+ *  This is used in tandem with
+ *  FLAC__stream_encoder_set_max_residual_partition_order().
+ *
+ *  The partition order determines the context size in the residual.
+ *  The context size will be approximately <tt>blocksize / (2 ^ order)</tt>.
+ *
+ *  Set both min and max values to \c 0 to force a single context,
+ *  whose Rice parameter is based on the residual signal variance.
+ *  Otherwise, set a min and max order, and the encoder will search
+ *  all orders, using the mean of each context for its Rice parameter,
+ *  and use the best.
+ *
+ * \default \c 0
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_min_residual_partition_order(FLAC__StreamEncoder *encoder, unsigned value);
+
+/** Set the maximum partition order to search when coding the residual.
+ *  This is used in tandem with
+ *  FLAC__stream_encoder_set_min_residual_partition_order().
+ *
+ *  The partition order determines the context size in the residual.
+ *  The context size will be approximately <tt>blocksize / (2 ^ order)</tt>.
+ *
+ *  Set both min and max values to \c 0 to force a single context,
+ *  whose Rice parameter is based on the residual signal variance.
+ *  Otherwise, set a min and max order, and the encoder will search
+ *  all orders, using the mean of each context for its Rice parameter,
+ *  and use the best.
+ *
+ * \default \c 0
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_max_residual_partition_order(FLAC__StreamEncoder *encoder, unsigned value);
+
+/** Deprecated.  Setting this value has no effect.
+ *
+ * \default \c 0
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_rice_parameter_search_dist(FLAC__StreamEncoder *encoder, unsigned value);
+
+/** Set an estimate of the total samples that will be encoded.
+ *  This is merely an estimate and may be set to \c 0 if unknown.
+ *  This value will be written to the STREAMINFO block before encoding,
+ *  and can remove the need for the caller to rewrite the value later
+ *  if the value is known before encoding.
+ *
+ * \default \c 0
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_total_samples_estimate(FLAC__StreamEncoder *encoder, FLAC__uint64 value);
+
+/** Set the metadata blocks to be emitted to the stream before encoding.
+ *  A value of \c NULL, \c 0 implies no metadata; otherwise, supply an
+ *  array of pointers to metadata blocks.  The array is non-const since
+ *  the encoder may need to change the \a is_last flag inside them.
+ *  Otherwise, the encoder will not modify or free the blocks.  It is up
+ *  to the caller to free the metadata blocks after encoding.
+ *
+ * \note
+ * The encoder stores only the \a metadata pointer; the passed-in array
+ * must survive at least until after FLAC__stream_encoder_init() returns.
+ * Do not modify the array or free the blocks until then.
+ *
+ * \note
+ * The STREAMINFO block is always written and no STREAMINFO block may
+ * occur in the supplied array.
+ *
+ * \note
+ * By default the encoder does not create a SEEKTABLE.  If one is supplied
+ * in the \a metadata array it will be written verbatim.  However by itself
+ * this is not very useful as the user will not know the stream offsets for
+ * the seekpoints ahead of time.  You must use the seekable stream encoder
+ * to generate a legal seektable
+ * (see FLAC__seekable_stream_encoder_set_metadata())
+ *
+ * \note
+ * A VORBIS_COMMENT block may be supplied.  The vendor string in it
+ * will be ignored.  libFLAC will use it's own vendor string. libFLAC
+ * will not modify the passed-in VORBIS_COMMENT's vendor string, it
+ * will simply write it's own into the stream.  If no VORBIS_COMMENT
+ * block is present in the \a metadata array, libFLAC will write an
+ * empty one, containing only the vendor string.
+ *
+ * \default \c NULL, 0
+ * \param  encoder     An encoder instance to set.
+ * \param  metadata    See above.
+ * \param  num_blocks  See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_metadata(FLAC__StreamEncoder *encoder, FLAC__StreamMetadata **metadata, unsigned num_blocks);
+
+/** Set the write callback.
+ *  The supplied function will be called by the encoder anytime there is raw
+ *  encoded data ready to write.  It may include metadata mixed with encoded
+ *  audio frames and the data is not guaranteed to be aligned on frame or
+ *  metadata block boundaries.
+ *
+ *  The only duty of the callback is to write out the \a bytes worth of data
+ *  in \a buffer to the current position in the output stream.  The arguments
+ *  \a samples and \a current_frame are purely informational.  If \a samples
+ *  is greater than \c 0, then \a current_frame will hold the current frame
+ *  number that is being written; otherwise, the write callback is being called
+ *  to write metadata.
+ *
+ * \note
+ * The callback is mandatory and must be set before initialization.
+ *
+ * \default \c NULL
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ *    \code value != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_write_callback(FLAC__StreamEncoder *encoder, FLAC__StreamEncoderWriteCallback value);
+
+/** Set the metadata callback.
+ *  The supplied function will be called once at the end of encoding with
+ *  the populated STREAMINFO structure.  This is so file encoders can seek
+ *  back to the beginning of the file and write the STREAMINFO block with
+ *  the correct statistics after encoding (like minimum/maximum frame size
+ *  and total samples).
+ *
+ * \note
+ * The callback is mandatory and must be set before initialization.
+ *
+ * \default \c NULL
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ *    \code value != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_metadata_callback(FLAC__StreamEncoder *encoder, FLAC__StreamEncoderMetadataCallback value);
+
+/** Set the client data to be passed back to callbacks.
+ *  This value will be supplied to callbacks in their \a client_data
+ *  argument.
+ *
+ * \default \c NULL
+ * \param  encoder  An encoder instance to set.
+ * \param  value    See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_client_data(FLAC__StreamEncoder *encoder, void *value);
+
+/** Get the current encoder state.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__StreamEncoderState
+ *    The current encoder state.
+ */
+FLAC_API FLAC__StreamEncoderState FLAC__stream_encoder_get_state(const FLAC__StreamEncoder *encoder);
+
+/** Get the state of the verify stream decoder.
+ *  Useful when the stream encoder state is
+ *  \c FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__StreamDecoderState
+ *    The verify stream decoder state.
+ */
+FLAC_API FLAC__StreamDecoderState FLAC__stream_encoder_get_verify_decoder_state(const FLAC__StreamEncoder *encoder);
+
+/** Get the current encoder state as a C string.
+ *  This version automatically resolves
+ *  \c FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR by getting the
+ *  verify decoder's state.
+ *
+ * \param  encoder  A encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval const char *
+ *    The encoder state as a C string.  Do not modify the contents.
+ */
+FLAC_API const char *FLAC__stream_encoder_get_resolved_state_string(const FLAC__StreamEncoder *encoder);
+
+/** Get relevant values about the nature of a verify decoder error.
+ *  Useful when the stream encoder state is
+ *  \c FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR.  The arguments should
+ *  be addresses in which the stats will be returned, or NULL if value
+ *  is not desired.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \param  absolute_sample  The absolute sample number of the mismatch.
+ * \param  frame_number  The number of the frame in which the mismatch occurred.
+ * \param  channel       The channel in which the mismatch occurred.
+ * \param  sample        The number of the sample (relative to the frame) in
+ *                       which the mismatch occurred.
+ * \param  expected      The expected value for the sample in question.
+ * \param  got           The actual value returned by the decoder.
+ * \assert
+ *    \code encoder != NULL \endcode
+ */
+FLAC_API void FLAC__stream_encoder_get_verify_decoder_error_stats(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_sample, unsigned *frame_number, unsigned *channel, unsigned *sample, FLAC__int32 *expected, FLAC__int32 *got);
+
+/** Get the "verify" flag.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See FLAC__stream_encoder_set_verify().
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_get_verify(const FLAC__StreamEncoder *encoder);
+
+/** Get the "streamable subset" flag.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See FLAC__stream_encoder_set_streamable_subset().
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_get_streamable_subset(const FLAC__StreamEncoder *encoder);
+
+/** Get the "mid/side stereo coding" flag.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See FLAC__stream_encoder_get_do_mid_side_stereo().
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_get_do_mid_side_stereo(const FLAC__StreamEncoder *encoder);
+
+/** Get the "adaptive mid/side switching" flag.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See FLAC__stream_encoder_set_loose_mid_side_stereo().
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_get_loose_mid_side_stereo(const FLAC__StreamEncoder *encoder);
+
+/** Get the number of input channels being processed.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval unsigned
+ *    See FLAC__stream_encoder_set_channels().
+ */
+FLAC_API unsigned FLAC__stream_encoder_get_channels(const FLAC__StreamEncoder *encoder);
+
+/** Get the input sample resolution setting.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval unsigned
+ *    See FLAC__stream_encoder_set_bits_per_sample().
+ */
+FLAC_API unsigned FLAC__stream_encoder_get_bits_per_sample(const FLAC__StreamEncoder *encoder);
+
+/** Get the input sample rate setting.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval unsigned
+ *    See FLAC__stream_encoder_set_sample_rate().
+ */
+FLAC_API unsigned FLAC__stream_encoder_get_sample_rate(const FLAC__StreamEncoder *encoder);
+
+/** Get the blocksize setting.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval unsigned
+ *    See FLAC__stream_encoder_set_blocksize().
+ */
+FLAC_API unsigned FLAC__stream_encoder_get_blocksize(const FLAC__StreamEncoder *encoder);
+
+/** Get the maximum LPC order setting.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval unsigned
+ *    See FLAC__stream_encoder_set_max_lpc_order().
+ */
+FLAC_API unsigned FLAC__stream_encoder_get_max_lpc_order(const FLAC__StreamEncoder *encoder);
+
+/** Get the quantized linear predictor coefficient precision setting.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval unsigned
+ *    See FLAC__stream_encoder_set_qlp_coeff_precision().
+ */
+FLAC_API unsigned FLAC__stream_encoder_get_qlp_coeff_precision(const FLAC__StreamEncoder *encoder);
+
+/** Get the qlp coefficient precision search flag.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See FLAC__stream_encoder_set_do_qlp_coeff_prec_search().
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_get_do_qlp_coeff_prec_search(const FLAC__StreamEncoder *encoder);
+
+/** Get the "escape coding" flag.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See FLAC__stream_encoder_set_do_escape_coding().
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_get_do_escape_coding(const FLAC__StreamEncoder *encoder);
+
+/** Get the exhaustive model search flag.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See FLAC__stream_encoder_set_do_exhaustive_model_search().
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_get_do_exhaustive_model_search(const FLAC__StreamEncoder *encoder);
+
+/** Get the minimum residual partition order setting.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval unsigned
+ *    See FLAC__stream_encoder_set_min_residual_partition_order().
+ */
+FLAC_API unsigned FLAC__stream_encoder_get_min_residual_partition_order(const FLAC__StreamEncoder *encoder);
+
+/** Get maximum residual partition order setting.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval unsigned
+ *    See FLAC__stream_encoder_set_max_residual_partition_order().
+ */
+FLAC_API unsigned FLAC__stream_encoder_get_max_residual_partition_order(const FLAC__StreamEncoder *encoder);
+
+/** Get the Rice parameter search distance setting.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval unsigned
+ *    See FLAC__stream_encoder_set_rice_parameter_search_dist().
+ */
+FLAC_API unsigned FLAC__stream_encoder_get_rice_parameter_search_dist(const FLAC__StreamEncoder *encoder);
+
+/** Get the previously set estimate of the total samples to be encoded.
+ *  The encoder merely mimics back the value given to
+ *  FLAC__stream_encoder_set_total_samples_estimate() since it has no
+ *  other way of knowing how many samples the user will encode.
+ *
+ * \param  encoder  An encoder instance to set.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__uint64
+ *    See FLAC__stream_encoder_get_total_samples_estimate().
+ */
+FLAC_API FLAC__uint64 FLAC__stream_encoder_get_total_samples_estimate(const FLAC__StreamEncoder *encoder);
+
+/** Initialize the encoder instance.
+ *  Should be called after FLAC__stream_encoder_new() and
+ *  FLAC__stream_encoder_set_*() but before FLAC__stream_encoder_process()
+ *  or FLAC__stream_encoder_process_interleaved().  Will set and return
+ *  the encoder state, which will be FLAC__STREAM_ENCODER_OK if
+ *  initialization succeeded.
+ *
+ *  The call to FLAC__stream_encoder_init() currently will also immediately
+ *  call the write callback several times, once with the \c fLaC signature,
+ *  and once for each encoded metadata block.
+ *
+ * \param  encoder  An uninitialized encoder instance.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__StreamEncoderState
+ *    \c FLAC__STREAM_ENCODER_OK if initialization was successful; see
+ *    FLAC__StreamEncoderState for the meanings of other return values.
+ */
+FLAC_API FLAC__StreamEncoderState FLAC__stream_encoder_init(FLAC__StreamEncoder *encoder);
+
+/** Finish the encoding process.
+ *  Flushes the encoding buffer, releases resources, resets the encoder
+ *  settings to their defaults, and returns the encoder state to
+ *  FLAC__STREAM_ENCODER_UNINITIALIZED.  Note that this can generate
+ *  one or more write callbacks before returning, and will generate
+ *  a metadata callback.
+ *
+ *  In the event of a prematurely-terminated encode, it is not strictly
+ *  necessary to call this immediately before FLAC__stream_encoder_delete()
+ *  but it is good practice to match every FLAC__stream_encoder_init()
+ *  with a FLAC__stream_encoder_finish().
+ *
+ * \param  encoder  An uninitialized encoder instance.
+ * \assert
+ *    \code encoder != NULL \endcode
+ */
+FLAC_API void FLAC__stream_encoder_finish(FLAC__StreamEncoder *encoder);
+
+/** Submit data for encoding.
+ *  This version allows you to supply the input data via an array of
+ *  pointers, each pointer pointing to an array of \a samples samples
+ *  representing one channel.  The samples need not be block-aligned,
+ *  but each channel should have the same number of samples.
+ *
+ * \param  encoder  An initialized encoder instance in the OK state.
+ * \param  buffer   An array of pointers to each channel's signal.
+ * \param  samples  The number of samples in one channel.
+ * \assert
+ *    \code encoder != NULL \endcode
+ *    \code FLAC__stream_encoder_get_state(encoder) == FLAC__STREAM_ENCODER_OK \endcode
+ * \retval FLAC__bool
+ *    \c true if successful, else \c false; in this case, check the
+ *    encoder state with FLAC__stream_encoder_get_state() to see what
+ *    went wrong.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_process(FLAC__StreamEncoder *encoder, const FLAC__int32 * const buffer[], unsigned samples);
+
+/** Submit data for encoding.
+ *  This version allows you to supply the input data where the channels
+ *  are interleaved into a single array (i.e. channel0_sample0,
+ *  channel1_sample0, ... , channelN_sample0, channel0_sample1, ...).
+ *  The samples need not be block-aligned but they must be
+ *  sample-aligned, i.e. the first value should be channel0_sample0
+ *  and the last value channelN_sampleM.
+ *
+ * \param  encoder  An initialized encoder instance in the OK state.
+ * \param  buffer   An array of channel-interleaved data (see above).
+ * \param  samples  The number of samples in one channel, the same as for
+ *                  FLAC__stream_encoder_process().  For example, if
+ *                  encoding two channels, \c 1000 \a samples corresponds
+ *                  to a \a buffer of 2000 values.
+ * \assert
+ *    \code encoder != NULL \endcode
+ *    \code FLAC__stream_encoder_get_state(encoder) == FLAC__STREAM_ENCODER_OK \endcode
+ * \retval FLAC__bool
+ *    \c true if successful, else \c false; in this case, check the
+ *    encoder state with FLAC__stream_encoder_get_state() to see what
+ *    went wrong.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_process_interleaved(FLAC__StreamEncoder *encoder, const FLAC__int32 buffer[], unsigned samples);
+
+/* \} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/bitbuffer.c
@@ -1,0 +1,2530 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdlib.h> /* for malloc() */
+#include <string.h> /* for memcpy(), memset() */
+#include "private/bitbuffer.h"
+#include "private/bitmath.h"
+#include "private/crc.h"
+#include "FLAC/assert.h"
+
+/*
+ * Along the way you will see two versions of some functions, selected
+ * by a FLAC__NO_MANUAL_INLINING macro.  One is the simplified, more
+ * readable, and slow version, and the other is the same function
+ * where crucial parts have been manually inlined and are much faster.
+ *
+ */
+
+/*
+ * This should be at least twice as large as the largest number of blurbs
+ * required to represent any 'number' (in any encoding) you are going to
+ * read.  With FLAC this is on the order of maybe a few hundred bits.
+ * If the buffer is smaller than that, the decoder won't be able to read
+ * in a whole number that is in a variable length encoding (e.g. Rice).
+ *
+ * The number we are actually using here is based on what would be the
+ * approximate maximum size of a verbatim frame at the default block size,
+ * for CD audio (4096 sample * 4 bytes per sample), plus some wiggle room.
+ * 32kbytes sounds reasonable.  For kicks we subtract out 64 bytes for any
+ * alignment or malloc overhead.
+ *
+ * Increase this number to decrease the number of read callbacks, at the
+ * expense of using more memory.  Or decrease for the reverse effect,
+ * keeping in mind the limit from the first paragraph.
+ */
+static const unsigned FLAC__BITBUFFER_DEFAULT_CAPACITY = ((65536 - 64) * 8) / FLAC__BITS_PER_BLURB; /* blurbs */
+
+#if FLAC__BITS_PER_BLURB == 8
+#define FLAC__BITS_PER_BLURB_LOG2 3
+#define FLAC__BYTES_PER_BLURB 1
+#define FLAC__BLURB_ALL_ONES ((FLAC__byte)0xff)
+#define FLAC__BLURB_TOP_BIT_ONE ((FLAC__byte)0x80)
+#define BLURB_BIT_TO_MASK(b) (((FLAC__blurb)'\x80') >> (b))
+#define CRC16_UPDATE_BLURB(bb, blurb, crc) FLAC__CRC16_UPDATE((blurb), (crc));
+#elif FLAC__BITS_PER_BLURB == 32
+#define FLAC__BITS_PER_BLURB_LOG2 5
+#define FLAC__BYTES_PER_BLURB 4
+#define FLAC__BLURB_ALL_ONES ((FLAC__uint32)0xffffffff)
+#define FLAC__BLURB_TOP_BIT_ONE ((FLAC__uint32)0x80000000)
+#define BLURB_BIT_TO_MASK(b) (((FLAC__blurb)0x80000000) >> (b))
+#define CRC16_UPDATE_BLURB(bb, blurb, crc) crc16_update_blurb((bb), (blurb));
+#else
+/* ERROR, only sizes of 8 and 32 are supported */
+#endif
+
+#define FLAC__BLURBS_TO_BITS(blurbs) ((blurbs) << FLAC__BITS_PER_BLURB_LOG2)
+
+#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))
+
+/* adjust for compilers that can't understand using LLU suffix for uint64_t literals */
+#ifdef _MSC_VER
+#define FLAC__U64L(x) x
+#else
+#define FLAC__U64L(x) x##LLU
+#endif
+
+#ifndef FLaC__INLINE
+#define FLaC__INLINE
+#endif
+
+struct FLAC__BitBuffer {
+	FLAC__blurb *buffer;
+	unsigned capacity; /* in blurbs */
+	unsigned blurbs, bits;
+	unsigned total_bits; /* must always == FLAC__BITS_PER_BLURB*blurbs+bits */
+	unsigned consumed_blurbs, consumed_bits;
+	unsigned total_consumed_bits; /* must always == FLAC__BITS_PER_BLURB*consumed_blurbs+consumed_bits */
+	FLAC__uint16 read_crc16;
+#if FLAC__BITS_PER_BLURB == 32
+	unsigned crc16_align;
+#endif
+	FLAC__blurb save_head, save_tail;
+};
+
+#if FLAC__BITS_PER_BLURB == 32
+static void crc16_update_blurb(FLAC__BitBuffer *bb, FLAC__blurb blurb)
+{
+	if(bb->crc16_align == 0) {
+		FLAC__CRC16_UPDATE(blurb >> 24, bb->read_crc16);
+		FLAC__CRC16_UPDATE((blurb >> 16) & 0xff, bb->read_crc16);
+		FLAC__CRC16_UPDATE((blurb >> 8) & 0xff, bb->read_crc16);
+		FLAC__CRC16_UPDATE(blurb & 0xff, bb->read_crc16);
+	}
+	else if(bb->crc16_align == 8) {
+		FLAC__CRC16_UPDATE((blurb >> 16) & 0xff, bb->read_crc16);
+		FLAC__CRC16_UPDATE((blurb >> 8) & 0xff, bb->read_crc16);
+		FLAC__CRC16_UPDATE(blurb & 0xff, bb->read_crc16);
+	}
+	else if(bb->crc16_align == 16) {
+		FLAC__CRC16_UPDATE((blurb >> 8) & 0xff, bb->read_crc16);
+		FLAC__CRC16_UPDATE(blurb & 0xff, bb->read_crc16);
+	}
+	else if(bb->crc16_align == 24) {
+		FLAC__CRC16_UPDATE(blurb & 0xff, bb->read_crc16);
+	}
+	bb->crc16_align = 0;
+}
+#endif
+
+/*
+ * WATCHOUT: The current implentation is not friendly to shrinking, i.e. it
+ * does not shift left what is consumed, it just chops off the end, whether
+ * there is unconsumed data there or not.  This is OK because currently we
+ * never shrink the buffer, but if this ever changes, we'll have to do some
+ * fixups here.
+ */
+static FLAC__bool bitbuffer_resize_(FLAC__BitBuffer *bb, unsigned new_capacity)
+{
+	FLAC__blurb *new_buffer;
+
+	FLAC__ASSERT(0 != bb);
+	FLAC__ASSERT(0 != bb->buffer);
+
+	if(bb->capacity == new_capacity)
+		return true;
+
+	new_buffer = (FLAC__blurb*)calloc(new_capacity, sizeof(FLAC__blurb));
+	if(new_buffer == 0)
+		return false;
+	memcpy(new_buffer, bb->buffer, sizeof(FLAC__blurb)*min(bb->blurbs+(bb->bits?1:0), new_capacity));
+	if(new_capacity < bb->blurbs+(bb->bits?1:0)) {
+		bb->blurbs = new_capacity;
+		bb->bits = 0;
+		bb->total_bits = FLAC__BLURBS_TO_BITS(new_capacity);
+	}
+	if(new_capacity < bb->consumed_blurbs+(bb->consumed_bits?1:0)) {
+		bb->consumed_blurbs = new_capacity;
+		bb->consumed_bits = 0;
+		bb->total_consumed_bits = FLAC__BLURBS_TO_BITS(new_capacity);
+	}
+	free(bb->buffer); /* we've already asserted above that (0 != bb->buffer) */
+	bb->buffer = new_buffer;
+	bb->capacity = new_capacity;
+	return true;
+}
+
+static FLAC__bool bitbuffer_grow_(FLAC__BitBuffer *bb, unsigned min_blurbs_to_add)
+{
+	unsigned new_capacity;
+
+	FLAC__ASSERT(min_blurbs_to_add > 0);
+
+	new_capacity = max(bb->capacity * 2, bb->capacity + min_blurbs_to_add);
+	return bitbuffer_resize_(bb, new_capacity);
+}
+
+static FLAC__bool bitbuffer_ensure_size_(FLAC__BitBuffer *bb, unsigned bits_to_add)
+{
+	FLAC__ASSERT(0 != bb);
+	FLAC__ASSERT(0 != bb->buffer);
+
+	if(FLAC__BLURBS_TO_BITS(bb->capacity) < bb->total_bits + bits_to_add)
+		return bitbuffer_grow_(bb, (bits_to_add >> FLAC__BITS_PER_BLURB_LOG2) + 2);
+	else
+		return true;
+}
+
+static FLAC__bool bitbuffer_read_from_client_(FLAC__BitBuffer *bb, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data)
+{
+	unsigned bytes;
+	FLAC__byte *target;
+
+	/* first shift the unconsumed buffer data toward the front as much as possible */
+	if(bb->total_consumed_bits >= FLAC__BITS_PER_BLURB) {
+		unsigned l = 0, r = bb->consumed_blurbs, r_end = bb->blurbs + (bb->bits? 1:0);
+		for( ; r < r_end; l++, r++)
+			bb->buffer[l] = bb->buffer[r];
+		for( ; l < r_end; l++)
+			bb->buffer[l] = 0;
+		bb->blurbs -= bb->consumed_blurbs;
+		bb->total_bits -= FLAC__BLURBS_TO_BITS(bb->consumed_blurbs);
+		bb->consumed_blurbs = 0;
+		bb->total_consumed_bits = bb->consumed_bits;
+	}
+
+	/* grow if we need to */
+	if(bb->capacity <= 1) {
+		if(!bitbuffer_resize_(bb, 16))
+			return false;
+	}
+
+	/* set the target for reading, taking into account blurb alignment */
+#if FLAC__BITS_PER_BLURB == 8
+	/* blurb == byte, so no gyrations necessary: */
+	target = bb->buffer + bb->blurbs;
+	bytes = bb->capacity - bb->blurbs;
+#elif FLAC__BITS_PER_BLURB == 32
+	/* @@@ WATCHOUT: code currently only works for big-endian: */
+	FLAC__ASSERT((bb->bits & 7) == 0);
+	target = (FLAC__byte*)(bb->buffer + bb->blurbs) + (bb->bits >> 3);
+	bytes = ((bb->capacity - bb->blurbs) << 2) - (bb->bits >> 3); /* i.e. (bb->capacity - bb->blurbs) * FLAC__BYTES_PER_BLURB - (bb->bits / 8) */
+#else
+	FLAC__ASSERT(false); /* ERROR, only sizes of 8 and 32 are supported */
+#endif
+
+	/* finally, read in some data */
+	if(!read_callback(target, &bytes, client_data))
+		return false;
+
+	/* now we have to handle partial blurb cases: */
+#if FLAC__BITS_PER_BLURB == 8
+	/* blurb == byte, so no gyrations necessary: */
+	bb->blurbs += bytes;
+	bb->total_bits += FLAC__BLURBS_TO_BITS(bytes);
+#elif FLAC__BITS_PER_BLURB == 32
+	/* @@@ WATCHOUT: code currently only works for big-endian: */
+	{
+		const unsigned aligned_bytes = (bb->bits >> 3) + bytes;
+		bb->blurbs += (aligned_bytes >> 2); /* i.e. aligned_bytes / FLAC__BYTES_PER_BLURB */
+		bb->bits = (aligned_bytes & 3u) << 3; /* i.e. (aligned_bytes % FLAC__BYTES_PER_BLURB) * 8 */
+		bb->total_bits += (bytes << 3);
+	}
+#else
+	FLAC__ASSERT(false); /* ERROR, only sizes of 8 and 32 are supported */
+#endif
+	return true;
+}
+
+/***********************************************************************
+ *
+ * Class constructor/destructor
+ *
+ ***********************************************************************/
+
+FLAC__BitBuffer *FLAC__bitbuffer_new()
+{
+	FLAC__BitBuffer *bb = (FLAC__BitBuffer*)calloc(1, sizeof(FLAC__BitBuffer));
+
+	/* calloc() implies:
+		memset(bb, 0, sizeof(FLAC__BitBuffer));
+		bb->buffer = 0;
+		bb->capacity = 0;
+		bb->blurbs = bb->bits = bb->total_bits = 0;
+		bb->consumed_blurbs = bb->consumed_bits = bb->total_consumed_bits = 0;
+	*/
+	return bb;
+}
+
+void FLAC__bitbuffer_delete(FLAC__BitBuffer *bb)
+{
+	FLAC__ASSERT(0 != bb);
+
+	FLAC__bitbuffer_free(bb);
+	free(bb);
+}
+
+/***********************************************************************
+ *
+ * Public class methods
+ *
+ ***********************************************************************/
+
+FLAC__bool FLAC__bitbuffer_init(FLAC__BitBuffer *bb)
+{
+	FLAC__ASSERT(0 != bb);
+
+	bb->buffer = 0;
+	bb->capacity = 0;
+	bb->blurbs = bb->bits = bb->total_bits = 0;
+	bb->consumed_blurbs = bb->consumed_bits = bb->total_consumed_bits = 0;
+
+	return FLAC__bitbuffer_clear(bb);
+}
+
+FLAC__bool FLAC__bitbuffer_init_from(FLAC__BitBuffer *bb, const FLAC__byte buffer[], unsigned bytes)
+{
+	FLAC__ASSERT(0 != bb);
+	FLAC__ASSERT(bytes > 0);
+
+	if(!FLAC__bitbuffer_init(bb))
+		return false;
+
+	if(!bitbuffer_ensure_size_(bb, bytes << 3))
+		return false;
+
+	FLAC__ASSERT(0 != buffer);
+	/* @@@ WATCHOUT: code currently only works for 8-bits-per-blurb inclusive-or big-endian: */
+	memcpy((FLAC__byte*)bb->buffer, buffer, sizeof(FLAC__byte)*bytes);
+	bb->blurbs = bytes / FLAC__BYTES_PER_BLURB;
+	bb->bits = (bytes % FLAC__BYTES_PER_BLURB) << 3;
+	bb->total_bits = bytes << 3;
+	return true;
+}
+
+FLAC__bool FLAC__bitbuffer_concatenate_aligned(FLAC__BitBuffer *dest, const FLAC__BitBuffer *src)
+{
+	unsigned bits_to_add = src->total_bits - src->total_consumed_bits;
+
+	FLAC__ASSERT(0 != dest);
+	FLAC__ASSERT(0 != src);
+
+	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->blurbs, src->buffer+src->consumed_blurbs, sizeof(FLAC__blurb)*(src->blurbs-src->consumed_blurbs + ((src->bits)? 1:0)));
+	}
+	else if(dest->bits + bits_to_add > FLAC__BITS_PER_BLURB) {
+		dest->buffer[dest->blurbs] <<= (FLAC__BITS_PER_BLURB - dest->bits);
+		dest->buffer[dest->blurbs] |= (src->buffer[src->consumed_blurbs] & ((1u << (FLAC__BITS_PER_BLURB-dest->bits)) - 1));
+		memcpy(dest->buffer+dest->blurbs+1, src->buffer+src->consumed_blurbs+1, sizeof(FLAC__blurb)*(src->blurbs-src->consumed_blurbs-1 + ((src->bits)? 1:0)));
+	}
+	else {
+		dest->buffer[dest->blurbs] <<= bits_to_add;
+		dest->buffer[dest->blurbs] |= (src->buffer[src->consumed_blurbs] & ((1u << bits_to_add) - 1));
+	}
+	dest->bits = src->bits;
+	dest->total_bits += bits_to_add;
+	dest->blurbs = dest->total_bits / FLAC__BITS_PER_BLURB;
+
+	return true;
+}
+
+void FLAC__bitbuffer_free(FLAC__BitBuffer *bb)
+{
+	FLAC__ASSERT(0 != bb);
+
+	if(0 != bb->buffer)
+		free(bb->buffer);
+	bb->buffer = 0;
+	bb->capacity = 0;
+	bb->blurbs = bb->bits = bb->total_bits = 0;
+	bb->consumed_blurbs = bb->consumed_bits = bb->total_consumed_bits = 0;
+}
+
+FLAC__bool FLAC__bitbuffer_clear(FLAC__BitBuffer *bb)
+{
+	if(bb->buffer == 0) {
+		bb->capacity = FLAC__BITBUFFER_DEFAULT_CAPACITY;
+		bb->buffer = (FLAC__blurb*)calloc(bb->capacity, sizeof(FLAC__blurb));
+		if(bb->buffer == 0)
+			return false;
+	}
+	else {
+		memset(bb->buffer, 0, bb->blurbs + (bb->bits?1:0));
+	}
+	bb->blurbs = bb->bits = bb->total_bits = 0;
+	bb->consumed_blurbs = bb->consumed_bits = bb->total_consumed_bits = 0;
+	return true;
+}
+
+FLAC__bool FLAC__bitbuffer_clone(FLAC__BitBuffer *dest, const FLAC__BitBuffer *src)
+{
+	FLAC__ASSERT(0 != dest);
+	FLAC__ASSERT(0 != dest->buffer);
+	FLAC__ASSERT(0 != src);
+	FLAC__ASSERT(0 != src->buffer);
+
+	if(dest->capacity < src->capacity)
+		if(!bitbuffer_resize_(dest, src->capacity))
+			return false;
+	memcpy(dest->buffer, src->buffer, sizeof(FLAC__blurb)*min(src->capacity, src->blurbs+1));
+	dest->blurbs = src->blurbs;
+	dest->bits = src->bits;
+	dest->total_bits = src->total_bits;
+	dest->consumed_blurbs = src->consumed_blurbs;
+	dest->consumed_bits = src->consumed_bits;
+	dest->total_consumed_bits = src->total_consumed_bits;
+	dest->read_crc16 = src->read_crc16;
+	return true;
+}
+
+void FLAC__bitbuffer_reset_read_crc16(FLAC__BitBuffer *bb, FLAC__uint16 seed)
+{
+	FLAC__ASSERT(0 != bb);
+	FLAC__ASSERT(0 != bb->buffer);
+	FLAC__ASSERT((bb->consumed_bits & 7) == 0);
+
+	bb->read_crc16 = seed;
+#if FLAC__BITS_PER_BLURB == 8
+	/* no need to do anything */
+#elif FLAC__BITS_PER_BLURB == 32
+	bb->crc16_align = bb->consumed_bits;
+#else
+	FLAC__ASSERT(false); /* ERROR, only sizes of 8 and 32 are supported */
+#endif
+}
+
+FLAC__uint16 FLAC__bitbuffer_get_read_crc16(FLAC__BitBuffer *bb)
+{
+	FLAC__ASSERT(0 != bb);
+	FLAC__ASSERT(0 != bb->buffer);
+	FLAC__ASSERT((bb->bits & 7) == 0);
+	FLAC__ASSERT((bb->consumed_bits & 7) == 0);
+
+#if FLAC__BITS_PER_BLURB == 8
+	/* no need to do anything */
+#elif FLAC__BITS_PER_BLURB == 32
+	/*@@@ BUG: even though this probably can't happen with FLAC, need to fix the case where we are called here for the very first blurb and crc16_align is > 0 */
+	if(bb->bits == 0 || bb->consumed_blurbs < bb->blurbs) {
+		if(bb->consumed_bits == 8) {
+			const FLAC__blurb blurb = bb->buffer[bb->consumed_blurbs];
+			FLAC__CRC16_UPDATE(blurb >> 24, bb->read_crc16);
+		}
+		else if(bb->consumed_bits == 16) {
+			const FLAC__blurb blurb = bb->buffer[bb->consumed_blurbs];
+			FLAC__CRC16_UPDATE(blurb >> 24, bb->read_crc16);
+			FLAC__CRC16_UPDATE((blurb >> 16) & 0xff, bb->read_crc16);
+		}
+		else if(bb->consumed_bits == 24) {
+			const FLAC__blurb blurb = bb->buffer[bb->consumed_blurbs];
+			FLAC__CRC16_UPDATE(blurb >> 24, bb->read_crc16);
+			FLAC__CRC16_UPDATE((blurb >> 16) & 0xff, bb->read_crc16);
+			FLAC__CRC16_UPDATE((blurb >> 8) & 0xff, bb->read_crc16);
+		}
+	}
+	else {
+		if(bb->consumed_bits == 8) {
+			const FLAC__blurb blurb = bb->buffer[bb->consumed_blurbs];
+			FLAC__CRC16_UPDATE(blurb >> (bb->bits-8), bb->read_crc16);
+		}
+		else if(bb->consumed_bits == 16) {
+			const FLAC__blurb blurb = bb->buffer[bb->consumed_blurbs];
+			FLAC__CRC16_UPDATE(blurb >> (bb->bits-8), bb->read_crc16);
+			FLAC__CRC16_UPDATE((blurb >> (bb->bits-16)) & 0xff, bb->read_crc16);
+		}
+		else if(bb->consumed_bits == 24) {
+			const FLAC__blurb blurb = bb->buffer[bb->consumed_blurbs];
+			FLAC__CRC16_UPDATE(blurb >> (bb->bits-8), bb->read_crc16);
+			FLAC__CRC16_UPDATE((blurb >> (bb->bits-16)) & 0xff, bb->read_crc16);
+			FLAC__CRC16_UPDATE((blurb >> (bb->bits-24)) & 0xff, bb->read_crc16);
+		}
+	}
+	bb->crc16_align = bb->consumed_bits;
+#else
+	FLAC__ASSERT(false); /* ERROR, only sizes of 8 and 32 are supported */
+#endif
+	return bb->read_crc16;
+}
+
+FLAC__uint16 FLAC__bitbuffer_get_write_crc16(const FLAC__BitBuffer *bb)
+{
+	FLAC__ASSERT((bb->bits & 7) == 0); /* assert that we're byte-aligned */
+
+#if FLAC__BITS_PER_BLURB == 8
+	return FLAC__crc16(bb->buffer, bb->blurbs);
+#elif FLAC__BITS_PER_BLURB == 32
+	/* @@@ WATCHOUT: code currently only works for big-endian: */
+	return FLAC__crc16((FLAC__byte*)(bb->buffer), (bb->blurbs * FLAC__BYTES_PER_BLURB) + (bb->bits >> 3));
+#else
+	FLAC__ASSERT(false); /* ERROR, only sizes of 8 and 32 are supported */
+#endif
+}
+
+FLAC__byte FLAC__bitbuffer_get_write_crc8(const FLAC__BitBuffer *bb)
+{
+	FLAC__ASSERT(0 != bb);
+	FLAC__ASSERT((bb->bits & 7) == 0); /* assert that we're byte-aligned */
+	FLAC__ASSERT(bb->buffer[0] == 0xff); /* MAGIC NUMBER for the first byte of the sync code */
+#if FLAC__BITS_PER_BLURB == 8
+	return FLAC__crc8(bb->buffer, bb->blurbs);
+#elif FLAC__BITS_PER_BLURB == 32
+	/* @@@ WATCHOUT: code currently only works for big-endian: */
+	return FLAC__crc8((FLAC__byte*)(bb->buffer), (bb->blurbs * FLAC__BYTES_PER_BLURB) + (bb->bits >> 3));
+#else
+	FLAC__ASSERT(false); /* ERROR, only sizes of 8 and 32 are supported */
+#endif
+}
+
+FLAC__bool FLAC__bitbuffer_is_byte_aligned(const FLAC__BitBuffer *bb)
+{
+	return ((bb->bits & 7) == 0);
+}
+
+FLAC__bool FLAC__bitbuffer_is_consumed_byte_aligned(const FLAC__BitBuffer *bb)
+{
+	return ((bb->consumed_bits & 7) == 0);
+}
+
+unsigned FLAC__bitbuffer_bits_left_for_byte_alignment(const FLAC__BitBuffer *bb)
+{
+	return 8 - (bb->consumed_bits & 7);
+}
+
+unsigned FLAC__bitbuffer_get_input_bytes_unconsumed(const FLAC__BitBuffer *bb)
+{
+	FLAC__ASSERT((bb->consumed_bits & 7) == 0 && (bb->bits & 7) == 0);
+	return (bb->total_bits - bb->total_consumed_bits) >> 3;
+}
+
+void FLAC__bitbuffer_get_buffer(FLAC__BitBuffer *bb, const FLAC__byte **buffer, unsigned *bytes)
+{
+	FLAC__ASSERT((bb->consumed_bits & 7) == 0 && (bb->bits & 7) == 0);
+#if FLAC__BITS_PER_BLURB == 8
+	*buffer = bb->buffer + bb->consumed_blurbs;
+	*bytes = bb->blurbs - bb->consumed_blurbs;
+#elif FLAC__BITS_PER_BLURB == 32
+	/* @@@ WATCHOUT: code currently only works for big-endian: */
+	*buffer = (FLAC__byte*)(bb->buffer + bb->consumed_blurbs) + (bb->consumed_bits >> 3);
+	*bytes = (bb->total_bits - bb->total_consumed_bits) >> 3;
+#else
+	FLAC__ASSERT(false); /* ERROR, only sizes of 8 and 32 are supported */
+#endif
+}
+
+void FLAC__bitbuffer_release_buffer(FLAC__BitBuffer *bb)
+{
+#if FLAC__BITS_PER_BLURB == 8
+	(void)bb;
+#elif FLAC__BITS_PER_BLURB == 32
+	/* @@@ WATCHOUT: code currently only works for big-endian: */
+	(void)bb;
+#else
+	FLAC__ASSERT(false); /* ERROR, only sizes of 8 and 32 are supported */
+#endif
+}
+
+FLAC__bool FLAC__bitbuffer_write_zeroes(FLAC__BitBuffer *bb, unsigned bits)
+{
+	unsigned n;
+
+	FLAC__ASSERT(0 != bb);
+	FLAC__ASSERT(0 != bb->buffer);
+
+	if(bits == 0)
+		return true;
+	if(!bitbuffer_ensure_size_(bb, bits))
+		return false;
+	bb->total_bits += bits;
+	while(bits > 0) {
+		n = min(FLAC__BITS_PER_BLURB - bb->bits, bits);
+		bb->buffer[bb->blurbs] <<= n;
+		bits -= n;
+		bb->bits += n;
+		if(bb->bits == FLAC__BITS_PER_BLURB) {
+			bb->blurbs++;
+			bb->bits = 0;
+		}
+	}
+	return true;
+}
+
+FLaC__INLINE FLAC__bool FLAC__bitbuffer_write_raw_uint32(FLAC__BitBuffer *bb, FLAC__uint32 val, unsigned bits)
+{
+	unsigned n, k;
+
+	FLAC__ASSERT(0 != bb);
+	FLAC__ASSERT(0 != bb->buffer);
+
+	FLAC__ASSERT(bits <= 32);
+	if(bits == 0)
+		return true;
+	/* inline the size check so we don't incure a function call unnecessarily */
+	if(FLAC__BLURBS_TO_BITS(bb->capacity) < bb->total_bits + bits) {
+		if(!bitbuffer_ensure_size_(bb, bits))
+			return false;
+	}
+
+	/* zero-out unused bits; WATCHOUT: other code relies on this, so this needs to stay */
+	if(bits < 32) /* @@@ gcc seems to require this because the following line causes incorrect results when bits==32; investigate */
+		val &= (~(0xffffffff << bits)); /* zero-out unused bits */
+
+	bb->total_bits += bits;
+	while(bits > 0) {
+		n = FLAC__BITS_PER_BLURB - bb->bits;
+		if(n == FLAC__BITS_PER_BLURB) { /* i.e. bb->bits == 0 */
+			if(bits < FLAC__BITS_PER_BLURB) {
+				bb->buffer[bb->blurbs] = (FLAC__blurb)val;
+				bb->bits = bits;
+				break;
+			}
+			else if(bits == FLAC__BITS_PER_BLURB) {
+				bb->buffer[bb->blurbs++] = (FLAC__blurb)val;
+				break;
+			}
+			else {
+				k = bits - FLAC__BITS_PER_BLURB;
+				bb->buffer[bb->blurbs++] = (FLAC__blurb)(val >> k);
+				/* we know k < 32 so no need to protect against the gcc bug mentioned above */
+				val &= (~(0xffffffff << k));
+				bits -= FLAC__BITS_PER_BLURB;
+			}
+		}
+		else if(bits <= n) {
+			bb->buffer[bb->blurbs] <<= bits;
+			bb->buffer[bb->blurbs] |= val;
+			if(bits == n) {
+				bb->blurbs++;
+				bb->bits = 0;
+			}
+			else
+				bb->bits += bits;
+			break;
+		}
+		else {
+			k = bits - n;
+			bb->buffer[bb->blurbs] <<= n;
+			bb->buffer[bb->blurbs] |= (val >> k);
+			/* we know n > 0 so k < 32 so no need to protect against the gcc bug mentioned above */
+			val &= (~(0xffffffff << k));
+			bits -= n;
+			bb->blurbs++;
+			bb->bits = 0;
+		}
+	}
+
+	return true;
+}
+
+FLAC__bool FLAC__bitbuffer_write_raw_int32(FLAC__BitBuffer *bb, FLAC__int32 val, unsigned bits)
+{
+	return FLAC__bitbuffer_write_raw_uint32(bb, (FLAC__uint32)val, bits);
+}
+
+FLAC__bool FLAC__bitbuffer_write_raw_uint64(FLAC__BitBuffer *bb, FLAC__uint64 val, unsigned bits)
+{
+	static const FLAC__uint64 mask[] = {
+		0,
+		FLAC__U64L(0x0000000000000001), FLAC__U64L(0x0000000000000003), FLAC__U64L(0x0000000000000007), FLAC__U64L(0x000000000000000F),
+		FLAC__U64L(0x000000000000001F), FLAC__U64L(0x000000000000003F), FLAC__U64L(0x000000000000007F), FLAC__U64L(0x00000000000000FF),
+		FLAC__U64L(0x00000000000001FF), FLAC__U64L(0x00000000000003FF), FLAC__U64L(0x00000000000007FF), FLAC__U64L(0x0000000000000FFF),
+		FLAC__U64L(0x0000000000001FFF), FLAC__U64L(0x0000000000003FFF), FLAC__U64L(0x0000000000007FFF), FLAC__U64L(0x000000000000FFFF),
+		FLAC__U64L(0x000000000001FFFF), FLAC__U64L(0x000000000003FFFF), FLAC__U64L(0x000000000007FFFF), FLAC__U64L(0x00000000000FFFFF),
+		FLAC__U64L(0x00000000001FFFFF), FLAC__U64L(0x00000000003FFFFF), FLAC__U64L(0x00000000007FFFFF), FLAC__U64L(0x0000000000FFFFFF),
+		FLAC__U64L(0x0000000001FFFFFF), FLAC__U64L(0x0000000003FFFFFF), FLAC__U64L(0x0000000007FFFFFF), FLAC__U64L(0x000000000FFFFFFF),
+		FLAC__U64L(0x000000001FFFFFFF), FLAC__U64L(0x000000003FFFFFFF), FLAC__U64L(0x000000007FFFFFFF), FLAC__U64L(0x00000000FFFFFFFF),
+		FLAC__U64L(0x00000001FFFFFFFF), FLAC__U64L(0x00000003FFFFFFFF), FLAC__U64L(0x00000007FFFFFFFF), FLAC__U64L(0x0000000FFFFFFFFF),
+		FLAC__U64L(0x0000001FFFFFFFFF), FLAC__U64L(0x0000003FFFFFFFFF), FLAC__U64L(0x0000007FFFFFFFFF), FLAC__U64L(0x000000FFFFFFFFFF),
+		FLAC__U64L(0x000001FFFFFFFFFF), FLAC__U64L(0x000003FFFFFFFFFF), FLAC__U64L(0x000007FFFFFFFFFF), FLAC__U64L(0x00000FFFFFFFFFFF),
+		FLAC__U64L(0x00001FFFFFFFFFFF), FLAC__U64L(0x00003FFFFFFFFFFF), FLAC__U64L(0x00007FFFFFFFFFFF), FLAC__U64L(0x0000FFFFFFFFFFFF),
+		FLAC__U64L(0x0001FFFFFFFFFFFF), FLAC__U64L(0x0003FFFFFFFFFFFF), FLAC__U64L(0x0007FFFFFFFFFFFF), FLAC__U64L(0x000FFFFFFFFFFFFF),
+		FLAC__U64L(0x001FFFFFFFFFFFFF), FLAC__U64L(0x003FFFFFFFFFFFFF), FLAC__U64L(0x007FFFFFFFFFFFFF), FLAC__U64L(0x00FFFFFFFFFFFFFF),
+		FLAC__U64L(0x01FFFFFFFFFFFFFF), FLAC__U64L(0x03FFFFFFFFFFFFFF), FLAC__U64L(0x07FFFFFFFFFFFFFF), FLAC__U64L(0x0FFFFFFFFFFFFFFF),
+		FLAC__U64L(0x1FFFFFFFFFFFFFFF), FLAC__U64L(0x3FFFFFFFFFFFFFFF), FLAC__U64L(0x7FFFFFFFFFFFFFFF), FLAC__U64L(0xFFFFFFFFFFFFFFFF)
+	};
+	unsigned n, k;
+
+	FLAC__ASSERT(0 != bb);
+	FLAC__ASSERT(0 != bb->buffer);
+
+	FLAC__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 < FLAC__BITS_PER_BLURB) {
+				bb->buffer[bb->blurbs] = (FLAC__blurb)val;
+				bb->bits = bits;
+				break;
+			}
+			else if(bits == FLAC__BITS_PER_BLURB) {
+				bb->buffer[bb->blurbs++] = (FLAC__blurb)val;
+				break;
+			}
+			else {
+				k = bits - FLAC__BITS_PER_BLURB;
+				bb->buffer[bb->blurbs++] = (FLAC__blurb)(val >> k);
+				/* we know k < 64 so no need to protect against the gcc bug mentioned above */
+				val &= (~(FLAC__U64L(0xffffffffffffffff) << k));
+				bits -= FLAC__BITS_PER_BLURB;
+			}
+		}
+		else {
+			n = min(FLAC__BITS_PER_BLURB - bb->bits, bits);
+			k = bits - n;
+			bb->buffer[bb->blurbs] <<= n;
+			bb->buffer[bb->blurbs] |= (val >> k);
+			/* we know n > 0 so k < 64 so no need to protect against the gcc bug mentioned above */
+			val &= (~(FLAC__U64L(0xffffffffffffffff) << k));
+			bits -= n;
+			bb->bits += n;
+			if(bb->bits == FLAC__BITS_PER_BLURB) {
+				bb->blurbs++;
+				bb->bits = 0;
+			}
+		}
+	}
+
+	return true;
+}
+
+#if 0 /* UNUSED */
+FLAC__bool FLAC__bitbuffer_write_raw_int64(FLAC__BitBuffer *bb, FLAC__int64 val, unsigned bits)
+{
+	return FLAC__bitbuffer_write_raw_uint64(bb, (FLAC__uint64)val, bits);
+}
+#endif
+
+FLaC__INLINE FLAC__bool FLAC__bitbuffer_write_raw_uint32_little_endian(FLAC__BitBuffer *bb, FLAC__uint32 val)
+{
+	/* this doesn't need to be that fast as currently it is only used for vorbis comments */
+
+	/* NOTE: we rely on the fact that FLAC__bitbuffer_write_raw_uint32() masks out the unused bits */
+	if(!FLAC__bitbuffer_write_raw_uint32(bb, val, 8))
+		return false;
+	if(!FLAC__bitbuffer_write_raw_uint32(bb, val>>8, 8))
+		return false;
+	if(!FLAC__bitbuffer_write_raw_uint32(bb, val>>16, 8))
+		return false;
+	if(!FLAC__bitbuffer_write_raw_uint32(bb, val>>24, 8))
+		return false;
+
+	return true;
+}
+
+FLaC__INLINE FLAC__bool FLAC__bitbuffer_write_byte_block(FLAC__BitBuffer *bb, const FLAC__byte vals[], unsigned nvals)
+{
+	unsigned i;
+
+	/* this could be faster but currently we don't need it to be */
+	for(i = 0; i < nvals; i++) {
+		if(!FLAC__bitbuffer_write_raw_uint32(bb, (FLAC__uint32)(vals[i]), 8))
+			return false;
+	}
+
+	return true;
+}
+
+FLAC__bool FLAC__bitbuffer_write_unary_unsigned(FLAC__BitBuffer *bb, unsigned val)
+{
+	if(val < 32)
+		return FLAC__bitbuffer_write_raw_uint32(bb, 1, ++val);
+	else if(val < 64)
+		return FLAC__bitbuffer_write_raw_uint64(bb, 1, ++val);
+	else {
+		if(!FLAC__bitbuffer_write_zeroes(bb, val))
+			return false;
+		return FLAC__bitbuffer_write_raw_uint32(bb, 1, 1);
+	}
+}
+
+unsigned FLAC__bitbuffer_rice_bits(int val, unsigned parameter)
+{
+	unsigned msbs, uval;
+
+	/* fold signed to unsigned */
+	if(val < 0)
+		/* equivalent to
+		 *     (unsigned)(((--val) << 1) - 1);
+		 * but without the overflow problem at MININT
+		 */
+		uval = (unsigned)(((-(++val)) << 1) + 1);
+	else
+		uval = (unsigned)(val << 1);
+
+	msbs = uval >> parameter;
+
+	return 1 + parameter + msbs;
+}
+
+#if 0 /* UNUSED */
+unsigned FLAC__bitbuffer_golomb_bits_signed(int val, unsigned parameter)
+{
+	unsigned bits, msbs, uval;
+	unsigned k;
+
+	FLAC__ASSERT(parameter > 0);
+
+	/* fold signed to unsigned */
+	if(val < 0)
+		/* equivalent to
+		 *     (unsigned)(((--val) << 1) - 1);
+		 * but without the overflow problem at MININT
+		 */
+		uval = (unsigned)(((-(++val)) << 1) + 1);
+	else
+		uval = (unsigned)(val << 1);
+
+	k = FLAC__bitmath_ilog2(parameter);
+	if(parameter == 1u<<k) {
+		FLAC__ASSERT(k <= 30);
+
+		msbs = uval >> k;
+		bits = 1 + k + msbs;
+	}
+	else {
+		unsigned q, r, d;
+
+		d = (1 << (k+1)) - parameter;
+		q = uval / parameter;
+		r = uval - (q * parameter);
+
+		bits = 1 + q + k;
+		if(r >= d)
+			bits++;
+	}
+	return bits;
+}
+
+unsigned FLAC__bitbuffer_golomb_bits_unsigned(unsigned uval, unsigned parameter)
+{
+	unsigned bits, msbs;
+	unsigned k;
+
+	FLAC__ASSERT(parameter > 0);
+
+	k = FLAC__bitmath_ilog2(parameter);
+	if(parameter == 1u<<k) {
+		FLAC__ASSERT(k <= 30);
+
+		msbs = uval >> k;
+		bits = 1 + k + msbs;
+	}
+	else {
+		unsigned q, r, d;
+
+		d = (1 << (k+1)) - parameter;
+		q = uval / parameter;
+		r = uval - (q * parameter);
+
+		bits = 1 + q + k;
+		if(r >= d)
+			bits++;
+	}
+	return bits;
+}
+#endif /* UNUSED */
+
+#ifdef FLAC__SYMMETRIC_RICE
+FLAC__bool FLAC__bitbuffer_write_symmetric_rice_signed(FLAC__BitBuffer *bb, int val, unsigned parameter)
+{
+	unsigned total_bits, interesting_bits, msbs;
+	FLAC__uint32 pattern;
+
+	FLAC__ASSERT(0 != bb);
+	FLAC__ASSERT(0 != bb->buffer);
+	FLAC__ASSERT(parameter <= 31);
+
+	/* init pattern with the unary end bit and the sign bit */
+	if(val < 0) {
+		pattern = 3;
+		val = -val;
+	}
+	else
+		pattern = 2;
+
+	msbs = val >> parameter;
+	interesting_bits = 2 + parameter;
+	total_bits = interesting_bits + msbs;
+	pattern <<= parameter;
+	pattern |= (val & ((1<<parameter)-1)); /* the binary LSBs */
+
+	if(total_bits <= 32) {
+		if(!FLAC__bitbuffer_write_raw_uint32(bb, pattern, total_bits))
+			return false;
+	}
+	else {
+		/* write the unary MSBs */
+		if(!FLAC__bitbuffer_write_zeroes(bb, msbs))
+			return false;
+		/* write the unary end bit, the sign bit, and binary LSBs */
+		if(!FLAC__bitbuffer_write_raw_uint32(bb, pattern, interesting_bits))
+			return false;
+	}
+	return true;
+}
+
+#if 0 /* UNUSED */
+FLAC__bool FLAC__bitbuffer_write_symmetric_rice_signed_guarded(FLAC__BitBuffer *bb, int val, unsigned parameter, unsigned max_bits, FLAC__bool *overflow)
+{
+	unsigned total_bits, interesting_bits, msbs;
+	FLAC__uint32 pattern;
+
+	FLAC__ASSERT(0 != bb);
+	FLAC__ASSERT(0 != bb->buffer);
+	FLAC__ASSERT(parameter <= 31);
+
+	*overflow = false;
+
+	/* init pattern with the unary end bit and the sign bit */
+	if(val < 0) {
+		pattern = 3;
+		val = -val;
+	}
+	else
+		pattern = 2;
+
+	msbs = val >> parameter;
+	interesting_bits = 2 + parameter;
+	total_bits = interesting_bits + msbs;
+	pattern <<= parameter;
+	pattern |= (val & ((1<<parameter)-1)); /* the binary LSBs */
+
+	if(total_bits <= 32) {
+		if(!FLAC__bitbuffer_write_raw_uint32(bb, pattern, total_bits))
+			return false;
+	}
+	else if(total_bits > max_bits) {
+		*overflow = true;
+		return true;
+	}
+	else {
+		/* write the unary MSBs */
+		if(!FLAC__bitbuffer_write_zeroes(bb, msbs))
+			return false;
+		/* write the unary end bit, the sign bit, and binary LSBs */
+		if(!FLAC__bitbuffer_write_raw_uint32(bb, pattern, interesting_bits))
+			return false;
+	}
+	return true;
+}
+#endif /* UNUSED */
+
+FLAC__bool FLAC__bitbuffer_write_symmetric_rice_signed_escape(FLAC__BitBuffer *bb, int val, unsigned parameter)
+{
+	unsigned total_bits, val_bits;
+	FLAC__uint32 pattern;
+
+	FLAC__ASSERT(0 != bb);
+	FLAC__ASSERT(0 != bb->buffer);
+	FLAC__ASSERT(parameter <= 31);
+
+	val_bits = FLAC__bitmath_silog2(val);
+	total_bits = 2 + parameter + 5 + val_bits;
+
+	if(total_bits <= 32) {
+		pattern = 3;
+		pattern <<= (parameter + 5);
+		pattern |= val_bits;
+		pattern <<= val_bits;
+		pattern |= (val & ((1 << val_bits) - 1));
+		if(!FLAC__bitbuffer_write_raw_uint32(bb, pattern, total_bits))
+			return false;
+	}
+	else {
+		/* write the '-0' escape code first */
+		if(!FLAC__bitbuffer_write_raw_uint32(bb, 3u << parameter, 2+parameter))
+			return false;
+		/* write the length */
+		if(!FLAC__bitbuffer_write_raw_uint32(bb, val_bits, 5))
+			return false;
+		/* write the value */
+		if(!FLAC__bitbuffer_write_raw_int32(bb, val, val_bits))
+			return false;
+	}
+	return true;
+}
+#endif /* ifdef FLAC__SYMMETRIC_RICE */
+
+FLAC__bool FLAC__bitbuffer_write_rice_signed(FLAC__BitBuffer *bb, int val, unsigned parameter)
+{
+	unsigned total_bits, interesting_bits, msbs, uval;
+	FLAC__uint32 pattern;
+
+	FLAC__ASSERT(0 != bb);
+	FLAC__ASSERT(0 != bb->buffer);
+	FLAC__ASSERT(parameter <= 30);
+
+	/* fold signed to unsigned */
+	if(val < 0)
+		/* equivalent to
+		 *     (unsigned)(((--val) << 1) - 1);
+		 * but without the overflow problem at MININT
+		 */
+		uval = (unsigned)(((-(++val)) << 1) + 1);
+	else
+		uval = (unsigned)(val << 1);
+
+	msbs = uval >> parameter;
+	interesting_bits = 1 + parameter;
+	total_bits = interesting_bits + msbs;
+	pattern = 1 << parameter; /* the unary end bit */
+	pattern |= (uval & ((1<<parameter)-1)); /* the binary LSBs */
+
+	if(total_bits <= 32) {
+		if(!FLAC__bitbuffer_write_raw_uint32(bb, pattern, total_bits))
+			return false;
+	}
+	else {
+		/* write the unary MSBs */
+		if(!FLAC__bitbuffer_write_zeroes(bb, msbs))
+			return false;
+		/* write the unary end bit and binary LSBs */
+		if(!FLAC__bitbuffer_write_raw_uint32(bb, pattern, interesting_bits))
+			return false;
+	}
+	return true;
+}
+
+#if 0 /* UNUSED */
+FLAC__bool FLAC__bitbuffer_write_rice_signed_guarded(FLAC__BitBuffer *bb, int val, unsigned parameter, unsigned max_bits, FLAC__bool *overflow)
+{
+	unsigned total_bits, interesting_bits, msbs, uval;
+	FLAC__uint32 pattern;
+
+	FLAC__ASSERT(0 != bb);
+	FLAC__ASSERT(0 != bb->buffer);
+	FLAC__ASSERT(parameter <= 30);
+
+	*overflow = false;
+
+	/* fold signed to unsigned */
+	if(val < 0)
+		/* equivalent to
+		 *     (unsigned)(((--val) << 1) - 1);
+		 * but without the overflow problem at MININT
+		 */
+		uval = (unsigned)(((-(++val)) << 1) + 1);
+	else
+		uval = (unsigned)(val << 1);
+
+	msbs = uval >> parameter;
+	interesting_bits = 1 + parameter;
+	total_bits = interesting_bits + msbs;
+	pattern = 1 << parameter; /* the unary end bit */
+	pattern |= (uval & ((1<<parameter)-1)); /* the binary LSBs */
+
+	if(total_bits <= 32) {
+		if(!FLAC__bitbuffer_write_raw_uint32(bb, pattern, total_bits))
+			return false;
+	}
+	else if(total_bits > max_bits) {
+		*overflow = true;
+		return true;
+	}
+	else {
+		/* write the unary MSBs */
+		if(!FLAC__bitbuffer_write_zeroes(bb, msbs))
+			return false;
+		/* write the unary end bit and binary LSBs */
+		if(!FLAC__bitbuffer_write_raw_uint32(bb, pattern, interesting_bits))
+			return false;
+	}
+	return true;
+}
+#endif /* UNUSED */
+
+#if 0 /* UNUSED */
+FLAC__bool FLAC__bitbuffer_write_golomb_signed(FLAC__BitBuffer *bb, int val, unsigned parameter)
+{
+	unsigned total_bits, msbs, uval;
+	unsigned k;
+
+	FLAC__ASSERT(0 != bb);
+	FLAC__ASSERT(0 != bb->buffer);
+	FLAC__ASSERT(parameter > 0);
+
+	/* fold signed to unsigned */
+	if(val < 0)
+		/* equivalent to
+		 *     (unsigned)(((--val) << 1) - 1);
+		 * but without the overflow problem at MININT
+		 */
+		uval = (unsigned)(((-(++val)) << 1) + 1);
+	else
+		uval = (unsigned)(val << 1);
+
+	k = FLAC__bitmath_ilog2(parameter);
+	if(parameter == 1u<<k) {
+		unsigned pattern;
+
+		FLAC__ASSERT(k <= 30);
+
+		msbs = uval >> k;
+		total_bits = 1 + k + msbs;
+		pattern = 1 << k; /* the unary end bit */
+		pattern |= (uval & ((1u<<k)-1)); /* the binary LSBs */
+
+		if(total_bits <= 32) {
+			if(!FLAC__bitbuffer_write_raw_uint32(bb, pattern, total_bits))
+				return false;
+		}
+		else {
+			/* write the unary MSBs */
+			if(!FLAC__bitbuffer_write_zeroes(bb, msbs))
+				return false;
+			/* write the unary end bit and binary LSBs */
+			if(!FLAC__bitbuffer_write_raw_uint32(bb, pattern, k+1))
+				return false;
+		}
+	}
+	else {
+		unsigned q, r, d;
+
+		d = (1 << (k+1)) - parameter;
+		q = uval / parameter;
+		r = uval - (q * parameter);
+		/* write the unary MSBs */
+		if(!FLAC__bitbuffer_write_zeroes(bb, q))
+			return false;
+		/* write the unary end bit */
+		if(!FLAC__bitbuffer_write_raw_uint32(bb, 1, 1))
+			return false;
+		/* write the binary LSBs */
+		if(r >= d) {
+			if(!FLAC__bitbuffer_write_raw_uint32(bb, r+d, k+1))
+				return false;
+		}
+		else {
+			if(!FLAC__bitbuffer_write_raw_uint32(bb, r, k))
+				return false;
+		}
+	}
+	return true;
+}
+
+FLAC__bool FLAC__bitbuffer_write_golomb_unsigned(FLAC__BitBuffer *bb, unsigned uval, unsigned parameter)
+{
+	unsigned total_bits, msbs;
+	unsigned k;
+
+	FLAC__ASSERT(0 != bb);
+	FLAC__ASSERT(0 != bb->buffer);
+	FLAC__ASSERT(parameter > 0);
+
+	k = FLAC__bitmath_ilog2(parameter);
+	if(parameter == 1u<<k) {
+		unsigned pattern;
+
+		FLAC__ASSERT(k <= 30);
+
+		msbs = uval >> k;
+		total_bits = 1 + k + msbs;
+		pattern = 1 << k; /* the unary end bit */
+		pattern |= (uval & ((1u<<k)-1)); /* the binary LSBs */
+
+		if(total_bits <= 32) {
+			if(!FLAC__bitbuffer_write_raw_uint32(bb, pattern, total_bits))
+				return false;
+		}
+		else {
+			/* write the unary MSBs */
+			if(!FLAC__bitbuffer_write_zeroes(bb, msbs))
+				return false;
+			/* write the unary end bit and binary LSBs */
+			if(!FLAC__bitbuffer_write_raw_uint32(bb, pattern, k+1))
+				return false;
+		}
+	}
+	else {
+		unsigned q, r, d;
+
+		d = (1 << (k+1)) - parameter;
+		q = uval / parameter;
+		r = uval - (q * parameter);
+		/* write the unary MSBs */
+		if(!FLAC__bitbuffer_write_zeroes(bb, q))
+			return false;
+		/* write the unary end bit */
+		if(!FLAC__bitbuffer_write_raw_uint32(bb, 1, 1))
+			return false;
+		/* write the binary LSBs */
+		if(r >= d) {
+			if(!FLAC__bitbuffer_write_raw_uint32(bb, r+d, k+1))
+				return false;
+		}
+		else {
+			if(!FLAC__bitbuffer_write_raw_uint32(bb, r, k))
+				return false;
+		}
+	}
+	return true;
+}
+#endif /* UNUSED */
+
+FLAC__bool FLAC__bitbuffer_write_utf8_uint32(FLAC__BitBuffer *bb, FLAC__uint32 val)
+{
+	FLAC__bool ok = 1;
+
+	FLAC__ASSERT(0 != bb);
+	FLAC__ASSERT(0 != bb->buffer);
+
+	FLAC__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;
+}
+
+FLAC__bool FLAC__bitbuffer_write_utf8_uint64(FLAC__BitBuffer *bb, FLAC__uint64 val)
+{
+	FLAC__bool ok = 1;
+
+	FLAC__ASSERT(0 != bb);
+	FLAC__ASSERT(0 != bb->buffer);
+
+	FLAC__ASSERT(!(val & FLAC__U64L(0xFFFFFFF000000000))); /* this version only handles 36 bits */
+
+	if(val < 0x80) {
+		return FLAC__bitbuffer_write_raw_uint32(bb, (FLAC__uint32)val, 8);
+	}
+	else if(val < 0x800) {
+		ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0xC0 | (FLAC__uint32)(val>>6), 8);
+		ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (FLAC__uint32)(val&0x3F), 8);
+	}
+	else if(val < 0x10000) {
+		ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0xE0 | (FLAC__uint32)(val>>12), 8);
+		ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8);
+		ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (FLAC__uint32)(val&0x3F), 8);
+	}
+	else if(val < 0x200000) {
+		ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0xF0 | (FLAC__uint32)(val>>18), 8);
+		ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (FLAC__uint32)((val>>12)&0x3F), 8);
+		ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8);
+		ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (FLAC__uint32)(val&0x3F), 8);
+	}
+	else if(val < 0x4000000) {
+		ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0xF8 | (FLAC__uint32)(val>>24), 8);
+		ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (FLAC__uint32)((val>>18)&0x3F), 8);
+		ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (FLAC__uint32)((val>>12)&0x3F), 8);
+		ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8);
+		ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (FLAC__uint32)(val&0x3F), 8);
+	}
+	else if(val < 0x80000000) {
+		ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0xFC | (FLAC__uint32)(val>>30), 8);
+		ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (FLAC__uint32)((val>>24)&0x3F), 8);
+		ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (FLAC__uint32)((val>>18)&0x3F), 8);
+		ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (FLAC__uint32)((val>>12)&0x3F), 8);
+		ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8);
+		ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (FLAC__uint32)(val&0x3F), 8);
+	}
+	else {
+		ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0xFE, 8);
+		ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (FLAC__uint32)((val>>30)&0x3F), 8);
+		ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (FLAC__uint32)((val>>24)&0x3F), 8);
+		ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (FLAC__uint32)((val>>18)&0x3F), 8);
+		ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (FLAC__uint32)((val>>12)&0x3F), 8);
+		ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8);
+		ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (FLAC__uint32)(val&0x3F), 8);
+	}
+
+	return ok;
+}
+
+FLAC__bool FLAC__bitbuffer_zero_pad_to_byte_boundary(FLAC__BitBuffer *bb)
+{
+	/* 0-pad to byte boundary */
+	if(bb->bits & 7u)
+		return FLAC__bitbuffer_write_zeroes(bb, 8 - (bb->bits & 7u));
+	else
+		return true;
+}
+
+FLAC__bool FLAC__bitbuffer_peek_bit(FLAC__BitBuffer *bb, unsigned *val, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data)
+{
+	/* to avoid a drastic speed penalty we don't:
+	FLAC__ASSERT(0 != bb);
+	FLAC__ASSERT(0 != bb->buffer);
+	FLAC__ASSERT(bb->bits == 0);
+	*/
+
+	while(1) {
+		if(bb->total_consumed_bits < bb->total_bits) {
+			*val = (bb->buffer[bb->consumed_blurbs] & BLURB_BIT_TO_MASK(bb->consumed_bits))? 1 : 0;
+			return true;
+		}
+		else {
+			if(!bitbuffer_read_from_client_(bb, read_callback, client_data))
+				return false;
+		}
+	}
+}
+
+FLAC__bool FLAC__bitbuffer_read_bit(FLAC__BitBuffer *bb, unsigned *val, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data)
+{
+	/* to avoid a drastic speed penalty we don't:
+	FLAC__ASSERT(0 != bb);
+	FLAC__ASSERT(0 != bb->buffer);
+	FLAC__ASSERT(bb->bits == 0);
+	*/
+
+	while(1) {
+		if(bb->total_consumed_bits < bb->total_bits) {
+			*val = (bb->buffer[bb->consumed_blurbs] & BLURB_BIT_TO_MASK(bb->consumed_bits))? 1 : 0;
+			bb->consumed_bits++;
+			if(bb->consumed_bits == FLAC__BITS_PER_BLURB) {
+				CRC16_UPDATE_BLURB(bb, bb->buffer[bb->consumed_blurbs], bb->read_crc16);
+				bb->consumed_blurbs++;
+				bb->consumed_bits = 0;
+			}
+			bb->total_consumed_bits++;
+			return true;
+		}
+		else {
+			if(!bitbuffer_read_from_client_(bb, read_callback, client_data))
+				return false;
+		}
+	}
+}
+
+FLAC__bool FLAC__bitbuffer_read_bit_to_uint32(FLAC__BitBuffer *bb, FLAC__uint32 *val, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data)
+{
+	/* to avoid a drastic speed penalty we don't:
+	FLAC__ASSERT(0 != bb);
+	FLAC__ASSERT(0 != bb->buffer);
+	FLAC__ASSERT(bb->bits == 0);
+	*/
+
+	while(1) {
+		if(bb->total_consumed_bits < bb->total_bits) {
+			*val <<= 1;
+			*val |= (bb->buffer[bb->consumed_blurbs] & BLURB_BIT_TO_MASK(bb->consumed_bits))? 1 : 0;
+			bb->consumed_bits++;
+			if(bb->consumed_bits == FLAC__BITS_PER_BLURB) {
+				CRC16_UPDATE_BLURB(bb, bb->buffer[bb->consumed_blurbs], bb->read_crc16);
+				bb->consumed_blurbs++;
+				bb->consumed_bits = 0;
+			}
+			bb->total_consumed_bits++;
+			return true;
+		}
+		else {
+			if(!bitbuffer_read_from_client_(bb, read_callback, client_data))
+				return false;
+		}
+	}
+}
+
+FLAC__bool FLAC__bitbuffer_read_bit_to_uint64(FLAC__BitBuffer *bb, FLAC__uint64 *val, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data)
+{
+	/* to avoid a drastic speed penalty we don't:
+	FLAC__ASSERT(0 != bb);
+	FLAC__ASSERT(0 != bb->buffer);
+	FLAC__ASSERT(bb->bits == 0);
+	*/
+
+	while(1) {
+		if(bb->total_consumed_bits < bb->total_bits) {
+			*val <<= 1;
+			*val |= (bb->buffer[bb->consumed_blurbs] & BLURB_BIT_TO_MASK(bb->consumed_bits))? 1 : 0;
+			bb->consumed_bits++;
+			if(bb->consumed_bits == FLAC__BITS_PER_BLURB) {
+				CRC16_UPDATE_BLURB(bb, bb->buffer[bb->consumed_blurbs], bb->read_crc16);
+				bb->consumed_blurbs++;
+				bb->consumed_bits = 0;
+			}
+			bb->total_consumed_bits++;
+			return true;
+		}
+		else {
+			if(!bitbuffer_read_from_client_(bb, read_callback, client_data))
+				return false;
+		}
+	}
+}
+
+FLaC__INLINE FLAC__bool FLAC__bitbuffer_read_raw_uint32(FLAC__BitBuffer *bb, FLAC__uint32 *val, const unsigned bits, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data)
+#ifdef FLAC__NO_MANUAL_INLINING
+{
+	unsigned i;
+
+	FLAC__ASSERT(0 != bb);
+	FLAC__ASSERT(0 != bb->buffer);
+
+	FLAC__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;
+}
+#else
+{
+	unsigned i, bits_ = bits;
+	FLAC__uint32 v = 0;
+
+	FLAC__ASSERT(0 != bb);
+	FLAC__ASSERT(0 != bb->buffer);
+
+	FLAC__ASSERT(bits <= 32);
+	FLAC__ASSERT((bb->capacity*FLAC__BITS_PER_BLURB) * 2 >= bits);
+
+	if(bits == 0) {
+		*val = 0;
+		return true;
+	}
+
+	while(bb->total_consumed_bits + bits > bb->total_bits) {
+		if(!bitbuffer_read_from_client_(bb, read_callback, client_data))
+			return false;
+	}
+#if FLAC__BITS_PER_BLURB > 8
+	if(bb->bits == 0 || bb->consumed_blurbs < bb->blurbs) { /*@@@ comment on why this is here*/
+#endif
+		if(bb->consumed_bits) {
+			i = FLAC__BITS_PER_BLURB - bb->consumed_bits;
+			if(i <= bits_) {
+				v = bb->buffer[bb->consumed_blurbs] & (FLAC__BLURB_ALL_ONES >> bb->consumed_bits);
+				bits_ -= i;
+				CRC16_UPDATE_BLURB(bb, bb->buffer[bb->consumed_blurbs], bb->read_crc16);
+				bb->consumed_blurbs++;
+				bb->consumed_bits = 0;
+				/* we hold off updating bb->total_consumed_bits until the end */
+			}
+			else {
+				*val = (bb->buffer[bb->consumed_blurbs] & (FLAC__BLURB_ALL_ONES >> bb->consumed_bits)) >> (i-bits_);
+				bb->consumed_bits += bits_;
+				bb->total_consumed_bits += bits_;
+				return true;
+			}
+		}
+#if FLAC__BITS_PER_BLURB == 32
+		/* note that we know bits_ cannot be > 32 because of previous assertions */
+		if(bits_ == FLAC__BITS_PER_BLURB) {
+			v = bb->buffer[bb->consumed_blurbs];
+			CRC16_UPDATE_BLURB(bb, v, bb->read_crc16);
+			bb->consumed_blurbs++;
+			/* bb->consumed_bits is already 0 */
+			bb->total_consumed_bits += bits;
+			*val = v;
+			return true;
+		}
+#else
+		while(bits_ >= FLAC__BITS_PER_BLURB) {
+			v <<= FLAC__BITS_PER_BLURB;
+			v |= bb->buffer[bb->consumed_blurbs];
+			bits_ -= FLAC__BITS_PER_BLURB;
+			CRC16_UPDATE_BLURB(bb, bb->buffer[bb->consumed_blurbs], bb->read_crc16);
+			bb->consumed_blurbs++;
+			/* bb->consumed_bits is already 0 */
+			/* we hold off updating bb->total_consumed_bits until the end */
+		}
+#endif
+		if(bits_ > 0) {
+			v <<= bits_;
+			v |= (bb->buffer[bb->consumed_blurbs] >> (FLAC__BITS_PER_BLURB-bits_));
+			bb->consumed_bits = bits_;
+			/* we hold off updating bb->total_consumed_bits until the end */
+		}
+		bb->total_consumed_bits += bits;
+		*val = v;
+#if FLAC__BITS_PER_BLURB > 8
+	}
+	else {
+		*val = 0;
+		for(i = 0; i < bits; i++) {
+			if(!FLAC__bitbuffer_read_bit_to_uint32(bb, val, read_callback, client_data))
+				return false;
+		}
+	}
+#endif
+	return true;
+}
+#endif
+
+FLAC__bool FLAC__bitbuffer_read_raw_int32(FLAC__BitBuffer *bb, FLAC__int32 *val, const unsigned bits, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data)
+#ifdef FLAC__NO_MANUAL_INLINING
+{
+	unsigned i;
+	FLAC__uint32 v;
+
+	FLAC__ASSERT(0 != bb);
+	FLAC__ASSERT(0 != bb->buffer);
+
+	FLAC__ASSERT(bits <= 32);
+
+	if(bits == 0) {
+		*val = 0;
+		return true;
+	}
+
+	v = 0;
+	for(i = 0; i < bits; i++) {
+		if(!FLAC__bitbuffer_read_bit_to_uint32(bb, &v, read_callback, client_data))
+			return false;
+	}
+
+	/* fix the sign */
+	i = 32 - bits;
+	if(i) {
+		v <<= i;
+		*val = (FLAC__int32)v;
+		*val >>= i;
+	}
+	else
+		*val = (FLAC__int32)v;
+
+	return true;
+}
+#else
+{
+	unsigned i, bits_ = bits;
+	FLAC__uint32 v = 0;
+
+	FLAC__ASSERT(0 != bb);
+	FLAC__ASSERT(0 != bb->buffer);
+
+	FLAC__ASSERT(bits <= 32);
+	FLAC__ASSERT((bb->capacity*FLAC__BITS_PER_BLURB) * 2 >= bits);
+
+	if(bits == 0) {
+		*val = 0;
+		return true;
+	}
+
+	while(bb->total_consumed_bits + bits > bb->total_bits) {
+		if(!bitbuffer_read_from_client_(bb, read_callback, client_data))
+			return false;
+	}
+#if FLAC__BITS_PER_BLURB > 8
+	if(bb->bits == 0 || bb->consumed_blurbs < bb->blurbs) { /*@@@ comment on why this is here*/
+#endif
+		if(bb->consumed_bits) {
+			i = FLAC__BITS_PER_BLURB - bb->consumed_bits;
+			if(i <= bits_) {
+				v = bb->buffer[bb->consumed_blurbs] & (FLAC__BLURB_ALL_ONES >> bb->consumed_bits);
+				bits_ -= i;
+				CRC16_UPDATE_BLURB(bb, bb->buffer[bb->consumed_blurbs], bb->read_crc16);
+				bb->consumed_blurbs++;
+				bb->consumed_bits = 0;
+				/* we hold off updating bb->total_consumed_bits until the end */
+			}
+			else {
+				/* bits_ must be < FLAC__BITS_PER_BLURB-1 if we get to here */
+				v = (bb->buffer[bb->consumed_blurbs] & (FLAC__BLURB_ALL_ONES >> bb->consumed_bits));
+				v <<= (32-i);
+				*val = (FLAC__int32)v;
+				*val >>= (32-bits_);
+				bb->consumed_bits += bits_;
+				bb->total_consumed_bits += bits_;
+				return true;
+			}
+		}
+#if FLAC__BITS_PER_BLURB == 32
+		/* note that we know bits_ cannot be > 32 because of previous assertions */
+		if(bits_ == FLAC__BITS_PER_BLURB) {
+			v = bb->buffer[bb->consumed_blurbs];
+			bits_ = 0;
+			CRC16_UPDATE_BLURB(bb, v, bb->read_crc16);
+			bb->consumed_blurbs++;
+			/* bb->consumed_bits is already 0 */
+			/* we hold off updating bb->total_consumed_bits until the end */
+		}
+#else
+		while(bits_ >= FLAC__BITS_PER_BLURB) {
+			v <<= FLAC__BITS_PER_BLURB;
+			v |= bb->buffer[bb->consumed_blurbs];
+			bits_ -= FLAC__BITS_PER_BLURB;
+			CRC16_UPDATE_BLURB(bb, bb->buffer[bb->consumed_blurbs], bb->read_crc16);
+			bb->consumed_blurbs++;
+			/* bb->consumed_bits is already 0 */
+			/* we hold off updating bb->total_consumed_bits until the end */
+		}
+#endif
+		if(bits_ > 0) {
+			v <<= bits_;
+			v |= (bb->buffer[bb->consumed_blurbs] >> (FLAC__BITS_PER_BLURB-bits_));
+			bb->consumed_bits = bits_;
+			/* we hold off updating bb->total_consumed_bits until the end */
+		}
+		bb->total_consumed_bits += bits;
+#if FLAC__BITS_PER_BLURB > 8
+	}
+	else {
+		for(i = 0; i < bits; i++) {
+			if(!FLAC__bitbuffer_read_bit_to_uint32(bb, &v, read_callback, client_data))
+				return false;
+		}
+	}
+#endif
+
+	/* fix the sign */
+	i = 32 - bits;
+	if(i) {
+		v <<= i;
+		*val = (FLAC__int32)v;
+		*val >>= i;
+	}
+	else
+		*val = (FLAC__int32)v;
+
+	return true;
+}
+#endif
+
+FLAC__bool FLAC__bitbuffer_read_raw_uint64(FLAC__BitBuffer *bb, FLAC__uint64 *val, const unsigned bits, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data)
+#ifdef FLAC__NO_MANUAL_INLINING
+{
+	unsigned i;
+
+	FLAC__ASSERT(0 != bb);
+	FLAC__ASSERT(0 != bb->buffer);
+
+	FLAC__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;
+}
+#else
+{
+	unsigned i, bits_ = bits;
+	FLAC__uint64 v = 0;
+
+	FLAC__ASSERT(0 != bb);
+	FLAC__ASSERT(0 != bb->buffer);
+
+	FLAC__ASSERT(bits <= 64);
+	FLAC__ASSERT((bb->capacity*FLAC__BITS_PER_BLURB) * 2 >= bits);
+
+	if(bits == 0) {
+		*val = 0;
+		return true;
+	}
+
+	while(bb->total_consumed_bits + bits > bb->total_bits) {
+		if(!bitbuffer_read_from_client_(bb, read_callback, client_data))
+			return false;
+	}
+#if FLAC__BITS_PER_BLURB > 8
+	if(bb->bits == 0 || bb->consumed_blurbs < bb->blurbs) { /*@@@ comment on why this is here*/
+#endif
+		if(bb->consumed_bits) {
+			i = FLAC__BITS_PER_BLURB - bb->consumed_bits;
+			if(i <= bits_) {
+				v = bb->buffer[bb->consumed_blurbs] & (FLAC__BLURB_ALL_ONES >> bb->consumed_bits);
+				bits_ -= i;
+				CRC16_UPDATE_BLURB(bb, bb->buffer[bb->consumed_blurbs], bb->read_crc16);
+				bb->consumed_blurbs++;
+				bb->consumed_bits = 0;
+				/* we hold off updating bb->total_consumed_bits until the end */
+			}
+			else {
+				*val = (bb->buffer[bb->consumed_blurbs] & (FLAC__BLURB_ALL_ONES >> bb->consumed_bits)) >> (i-bits_);
+				bb->consumed_bits += bits_;
+				bb->total_consumed_bits += bits_;
+				return true;
+			}
+		}
+		while(bits_ >= FLAC__BITS_PER_BLURB) {
+			v <<= FLAC__BITS_PER_BLURB;
+			v |= bb->buffer[bb->consumed_blurbs];
+			bits_ -= FLAC__BITS_PER_BLURB;
+			CRC16_UPDATE_BLURB(bb, bb->buffer[bb->consumed_blurbs], bb->read_crc16);
+			bb->consumed_blurbs++;
+			/* bb->consumed_bits is already 0 */
+			/* we hold off updating bb->total_consumed_bits until the end */
+		}
+		if(bits_ > 0) {
+			v <<= bits_;
+			v |= (bb->buffer[bb->consumed_blurbs] >> (FLAC__BITS_PER_BLURB-bits_));
+			bb->consumed_bits = bits_;
+			/* we hold off updating bb->total_consumed_bits until the end */
+		}
+		bb->total_consumed_bits += bits;
+		*val = v;
+#if FLAC__BITS_PER_BLURB > 8
+	}
+	else {
+		*val = 0;
+		for(i = 0; i < bits; i++) {
+			if(!FLAC__bitbuffer_read_bit_to_uint64(bb, val, read_callback, client_data))
+				return false;
+		}
+	}
+#endif
+	return true;
+}
+#endif
+
+#if 0 /* UNUSED */
+FLAC__bool FLAC__bitbuffer_read_raw_int64(FLAC__BitBuffer *bb, FLAC__int64 *val, const unsigned bits, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data)
+#ifdef FLAC__NO_MANUAL_INLINING
+{
+	unsigned i;
+	FLAC__uint64 v;
+
+	FLAC__ASSERT(0 != bb);
+	FLAC__ASSERT(0 != bb->buffer);
+
+	FLAC__ASSERT(bits <= 64);
+
+	v = 0;
+	for(i = 0; i < bits; i++) {
+		if(!FLAC__bitbuffer_read_bit_to_uint64(bb, &v, read_callback, client_data))
+			return false;
+	}
+	/* fix the sign */
+	i = 64 - bits;
+	if(i) {
+		v <<= i;
+		*val = (FLAC__int64)v;
+		*val >>= i;
+	}
+	else
+		*val = (FLAC__int64)v;
+
+	return true;
+}
+#else
+{
+	unsigned i, bits_ = bits;
+	FLAC__uint64 v = 0;
+
+	FLAC__ASSERT(0 != bb);
+	FLAC__ASSERT(0 != bb->buffer);
+
+	FLAC__ASSERT(bits <= 64);
+	FLAC__ASSERT((bb->capacity*FLAC__BITS_PER_BLURB) * 2 >= bits);
+
+	if(bits == 0) {
+		*val = 0;
+		return true;
+	}
+
+	while(bb->total_consumed_bits + bits > bb->total_bits) {
+		if(!bitbuffer_read_from_client_(bb, read_callback, client_data))
+			return false;
+	}
+#if FLAC__BITS_PER_BLURB > 8
+	if(bb->bits == 0 || bb->consumed_blurbs < bb->blurbs) { /*@@@ comment on why this is here*/
+#endif
+		if(bb->consumed_bits) {
+			i = FLAC__BITS_PER_BLURB - bb->consumed_bits;
+			if(i <= bits_) {
+				v = bb->buffer[bb->consumed_blurbs] & (FLAC__BLURB_ALL_ONES >> bb->consumed_bits);
+				bits_ -= i;
+				CRC16_UPDATE_BLURB(bb, bb->buffer[bb->consumed_blurbs], bb->read_crc16);
+				bb->consumed_blurbs++;
+				bb->consumed_bits = 0;
+				/* we hold off updating bb->total_consumed_bits until the end */
+			}
+			else {
+				/* bits_ must be < FLAC__BITS_PER_BLURB-1 if we get to here */
+				v = (bb->buffer[bb->consumed_blurbs] & (FLAC__BLURB_ALL_ONES >> bb->consumed_bits));
+				v <<= (64-i);
+				*val = (FLAC__int64)v;
+				*val >>= (64-bits_);
+				bb->consumed_bits += bits_;
+				bb->total_consumed_bits += bits_;
+				return true;
+			}
+		}
+		while(bits_ >= FLAC__BITS_PER_BLURB) {
+			v <<= FLAC__BITS_PER_BLURB;
+			v |= bb->buffer[bb->consumed_blurbs];
+			bits_ -= FLAC__BITS_PER_BLURB;
+			CRC16_UPDATE_BLURB(bb, bb->buffer[bb->consumed_blurbs], bb->read_crc16);
+			bb->consumed_blurbs++;
+			/* bb->consumed_bits is already 0 */
+			/* we hold off updating bb->total_consumed_bits until the end */
+		}
+		if(bits_ > 0) {
+			v <<= bits_;
+			v |= (bb->buffer[bb->consumed_blurbs] >> (FLAC__BITS_PER_BLURB-bits_));
+			bb->consumed_bits = bits_;
+			/* we hold off updating bb->total_consumed_bits until the end */
+		}
+		bb->total_consumed_bits += bits;
+#if FLAC__BITS_PER_BLURB > 8
+	}
+	else {
+		for(i = 0; i < bits; i++) {
+			if(!FLAC__bitbuffer_read_bit_to_uint64(bb, &v, read_callback, client_data))
+				return false;
+		}
+	}
+#endif
+
+	/* fix the sign */
+	i = 64 - bits;
+	if(i) {
+		v <<= i;
+		*val = (FLAC__int64)v;
+		*val >>= i;
+	}
+	else
+		*val = (FLAC__int64)v;
+
+	return true;
+}
+#endif
+#endif
+
+FLaC__INLINE FLAC__bool FLAC__bitbuffer_read_raw_uint32_little_endian(FLAC__BitBuffer *bb, FLAC__uint32 *val, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data)
+{
+	FLAC__uint32 x8, x32 = 0;
+
+	/* this doesn't need to be that fast as currently it is only used for vorbis comments */
+
+	if(!FLAC__bitbuffer_read_raw_uint32(bb, &x32, 8, read_callback, client_data))
+		return false;
+
+	if(!FLAC__bitbuffer_read_raw_uint32(bb, &x8, 8, read_callback, client_data))
+		return false;
+	x32 |= (x8 << 8);
+
+	if(!FLAC__bitbuffer_read_raw_uint32(bb, &x8, 8, read_callback, client_data))
+		return false;
+	x32 |= (x8 << 16);
+
+	if(!FLAC__bitbuffer_read_raw_uint32(bb, &x8, 8, read_callback, client_data))
+		return false;
+	x32 |= (x8 << 24);
+
+	*val = x32;
+	return true;
+}
+
+FLAC__bool FLAC__bitbuffer_skip_bits_no_crc(FLAC__BitBuffer *bb, unsigned bits, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data)
+{
+	/*
+	 * @@@ a slightly faster implementation is possible but
+	 * probably not that useful since this is only called a
+	 * couple of times in the metadata readers.
+	 */
+	FLAC__ASSERT(0 != bb);
+	FLAC__ASSERT(0 != bb->buffer);
+
+	if(bits > 0) {
+		const unsigned n = bb->consumed_bits & 7;
+	   	unsigned m;
+		FLAC__uint32 x;
+
+		if(n != 0) {
+			m = min(8-n, bits);
+			if(!FLAC__bitbuffer_read_raw_uint32(bb, &x, m, read_callback, client_data))
+				return false;
+			bits -= m;
+		}
+		m = bits / 8;
+		if(m > 0) {
+			if(!FLAC__bitbuffer_read_byte_block_aligned_no_crc(bb, 0, m, read_callback, client_data))
+				return false;
+			bits %= 8;
+		}
+		if(bits > 0) {
+			if(!FLAC__bitbuffer_read_raw_uint32(bb, &x, bits, read_callback, client_data))
+				return false;
+		}
+	}
+
+	return true;
+}
+
+FLAC__bool FLAC__bitbuffer_read_byte_block_aligned_no_crc(FLAC__BitBuffer *bb, FLAC__byte *val, unsigned nvals, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data)
+{
+	FLAC__ASSERT(0 != bb);
+	FLAC__ASSERT(0 != bb->buffer);
+	FLAC__ASSERT(FLAC__bitbuffer_is_byte_aligned(bb));
+	FLAC__ASSERT(FLAC__bitbuffer_is_consumed_byte_aligned(bb));
+#if FLAC__BITS_PER_BLURB == 8
+	while(nvals > 0) {
+		unsigned chunk = min(nvals, bb->blurbs - bb->consumed_blurbs);
+		if(chunk == 0) {
+			if(!bitbuffer_read_from_client_(bb, read_callback, client_data))
+				return false;
+		}
+		else {
+			if(0 != val) {
+				memcpy(val, bb->buffer + bb->consumed_blurbs, FLAC__BYTES_PER_BLURB * chunk);
+				val += FLAC__BYTES_PER_BLURB * chunk;
+			}
+			nvals -= chunk;
+			bb->consumed_blurbs += chunk;
+			bb->total_consumed_bits = (bb->consumed_blurbs << FLAC__BITS_PER_BLURB_LOG2);
+		}
+	}
+#else
+	@@@ need to write this still
+	FLAC__ASSERT(0);
+#endif
+
+	return true;
+}
+
+FLaC__INLINE FLAC__bool FLAC__bitbuffer_read_unary_unsigned(FLAC__BitBuffer *bb, unsigned *val, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data)
+#ifdef FLAC__NO_MANUAL_INLINING
+{
+	unsigned bit, val_ = 0;
+
+	FLAC__ASSERT(0 != bb);
+	FLAC__ASSERT(0 != bb->buffer);
+
+	while(1) {
+		if(!FLAC__bitbuffer_read_bit(bb, &bit, read_callback, client_data))
+			return false;
+		if(bit)
+			break;
+		else
+			val_++;
+	}
+	*val = val_;
+	return true;
+}
+#else
+{
+	unsigned i, val_ = 0;
+	unsigned total_blurbs_ = (bb->total_bits + (FLAC__BITS_PER_BLURB-1)) / FLAC__BITS_PER_BLURB;
+	FLAC__blurb b;
+
+	FLAC__ASSERT(0 != bb);
+	FLAC__ASSERT(0 != bb->buffer);
+
+#if FLAC__BITS_PER_BLURB > 8
+	if(bb->bits == 0 || bb->consumed_blurbs < bb->blurbs) { /*@@@ comment on why this is here*/
+#endif
+		if(bb->consumed_bits) {
+			b = bb->buffer[bb->consumed_blurbs] << bb->consumed_bits;
+			if(b) {
+				for(i = 0; !(b & FLAC__BLURB_TOP_BIT_ONE); i++)
+					b <<= 1;
+				*val = i;
+				i++;
+				bb->consumed_bits += i;
+				bb->total_consumed_bits += i;
+				if(bb->consumed_bits == FLAC__BITS_PER_BLURB) {
+					CRC16_UPDATE_BLURB(bb, bb->buffer[bb->consumed_blurbs], bb->read_crc16);
+					bb->consumed_blurbs++;
+					bb->consumed_bits = 0;
+				}
+				return true;
+			}
+			else {
+				val_ = FLAC__BITS_PER_BLURB - bb->consumed_bits;
+				CRC16_UPDATE_BLURB(bb, bb->buffer[bb->consumed_blurbs], bb->read_crc16);
+				bb->consumed_blurbs++;
+				bb->consumed_bits = 0;
+				bb->total_consumed_bits += val_;
+			}
+		}
+		while(1) {
+			if(bb->consumed_blurbs >= total_blurbs_) {
+				if(!bitbuffer_read_from_client_(bb, read_callback, client_data))
+					return false;
+				total_blurbs_ = (bb->total_bits + (FLAC__BITS_PER_BLURB-1)) / FLAC__BITS_PER_BLURB;
+			}
+			b = bb->buffer[bb->consumed_blurbs];
+			if(b) {
+				for(i = 0; !(b & FLAC__BLURB_TOP_BIT_ONE); i++)
+					b <<= 1;
+				val_ += i;
+				i++;
+				bb->consumed_bits = i;
+				*val = val_;
+				if(i == FLAC__BITS_PER_BLURB) {
+					CRC16_UPDATE_BLURB(bb, bb->buffer[bb->consumed_blurbs], bb->read_crc16);
+					bb->consumed_blurbs++;
+					bb->consumed_bits = 0;
+				}
+				bb->total_consumed_bits += i;
+				return true;
+			}
+			else {
+				val_ += FLAC__BITS_PER_BLURB;
+				CRC16_UPDATE_BLURB(bb, 0, bb->read_crc16);
+				bb->consumed_blurbs++;
+				/* bb->consumed_bits is already 0 */
+				bb->total_consumed_bits += FLAC__BITS_PER_BLURB;
+			}
+		}
+#if FLAC__BITS_PER_BLURB > 8
+	}
+	else {
+		while(1) {
+			if(!FLAC__bitbuffer_read_bit(bb, &i, read_callback, client_data))
+				return false;
+			if(i)
+				break;
+			else
+				val_++;
+		}
+		*val = val_;
+		return true;
+	}
+#endif
+}
+#endif
+
+#ifdef FLAC__SYMMETRIC_RICE
+FLAC__bool FLAC__bitbuffer_read_symmetric_rice_signed(FLAC__BitBuffer *bb, int *val, unsigned parameter, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data)
+{
+	FLAC__uint32 sign = 0, lsbs = 0, msbs = 0;
+
+	FLAC__ASSERT(0 != bb);
+	FLAC__ASSERT(0 != bb->buffer);
+	FLAC__ASSERT(parameter <= 31);
+
+	/* read the unary MSBs and end bit */
+	if(!FLAC__bitbuffer_read_unary_unsigned(bb, &msbs, read_callback, client_data))
+		return false;
+
+	/* 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;
+
+	/* compose the value */
+	*val = (msbs << parameter) | lsbs;
+	if(sign)
+		*val = -(*val);
+
+	return true;
+}
+#endif /* ifdef FLAC__SYMMETRIC_RICE */
+
+FLAC__bool FLAC__bitbuffer_read_rice_signed(FLAC__BitBuffer *bb, int *val, unsigned parameter, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data)
+{
+	FLAC__uint32 lsbs = 0, msbs = 0;
+	unsigned uval;
+
+	FLAC__ASSERT(0 != bb);
+	FLAC__ASSERT(0 != bb->buffer);
+	FLAC__ASSERT(parameter <= 31);
+
+	/* read the unary MSBs and end bit */
+	if(!FLAC__bitbuffer_read_unary_unsigned(bb, &msbs, 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;
+
+	/* compose the value */
+	uval = (msbs << parameter) | lsbs;
+	if(uval & 1)
+		*val = -((int)(uval >> 1)) - 1;
+	else
+		*val = (int)(uval >> 1);
+
+	return true;
+}
+
+FLAC__bool FLAC__bitbuffer_read_rice_signed_block(FLAC__BitBuffer *bb, int vals[], unsigned nvals, unsigned parameter, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data)
+{
+	const FLAC__blurb *buffer = bb->buffer;
+
+	unsigned i, j, val_i = 0;
+	unsigned cbits = 0, uval = 0, msbs = 0, lsbs_left = 0;
+	FLAC__blurb blurb, save_blurb;
+	unsigned state = 0; /* 0 = getting unary MSBs, 1 = getting binary LSBs */
+
+	FLAC__ASSERT(0 != bb);
+	FLAC__ASSERT(0 != bb->buffer);
+	FLAC__ASSERT(parameter <= 31);
+
+	if(nvals == 0)
+		return true;
+
+	i = bb->consumed_blurbs;
+	/*
+	 * We unroll the main loop to take care of partially consumed blurbs here.
+	 */
+	if(bb->consumed_bits > 0) {
+		save_blurb = blurb = buffer[i];
+		cbits = bb->consumed_bits;
+		blurb <<= cbits;
+
+		while(1) {
+			if(state == 0) {
+				if(blurb) {
+					for(j = 0; !(blurb & FLAC__BLURB_TOP_BIT_ONE); j++)
+						blurb <<= 1;
+					msbs += j;
+
+					/* dispose of the unary end bit */
+					blurb <<= 1;
+					j++;
+					cbits += j;
+
+					uval = 0;
+					lsbs_left = parameter;
+					state++;
+					if(cbits == FLAC__BITS_PER_BLURB) {
+						cbits = 0;
+						CRC16_UPDATE_BLURB(bb, save_blurb, bb->read_crc16);
+						break;
+					}
+				}
+				else {
+					msbs += FLAC__BITS_PER_BLURB - cbits;
+					cbits = 0;
+					CRC16_UPDATE_BLURB(bb, save_blurb, bb->read_crc16);
+					break;
+				}
+			}
+			else {
+				const unsigned available_bits = FLAC__BITS_PER_BLURB - cbits;
+				if(lsbs_left >= available_bits) {
+					uval <<= available_bits;
+					uval |= (blurb >> cbits);
+					cbits = 0;
+					CRC16_UPDATE_BLURB(bb, save_blurb, bb->read_crc16);
+
+					if(lsbs_left == available_bits) {
+						/* compose the value */
+						uval |= (msbs << parameter);
+						if(uval & 1)
+							vals[val_i++] = -((int)(uval >> 1)) - 1;
+						else
+							vals[val_i++] = (int)(uval >> 1);
+						if(val_i == nvals)
+							break;
+
+						msbs = 0;
+						state = 0;
+					}
+
+					lsbs_left -= available_bits;
+					break;
+				}
+				else {
+					uval <<= lsbs_left;
+					uval |= (blurb >> (FLAC__BITS_PER_BLURB - lsbs_left));
+					blurb <<= lsbs_left;
+					cbits += lsbs_left;
+
+					/* compose the value */
+					uval |= (msbs << parameter);
+					if(uval & 1)
+						vals[val_i++] = -((int)(uval >> 1)) - 1;
+					else
+						vals[val_i++] = (int)(uval >> 1);
+					if(val_i == nvals) {
+						/* back up one if we exited the for loop because we read all nvals but the end came in the middle of a blurb */
+						i--;
+						break;
+					}
+
+					msbs = 0;
+					state = 0;
+				}
+			}
+		}
+		i++;
+
+		bb->consumed_blurbs = i;
+		bb->consumed_bits = cbits;
+		bb->total_consumed_bits = (i << FLAC__BITS_PER_BLURB_LOG2) | cbits;
+	}
+
+	/*
+	 * Now that we are blurb-aligned the logic is slightly simpler
+	 */
+	while(val_i < nvals) {
+		for( ; i < bb->blurbs && val_i < nvals; i++) {
+			save_blurb = blurb = buffer[i];
+			cbits = 0;
+			while(1) {
+				if(state == 0) {
+					if(blurb) {
+						for(j = 0; !(blurb & FLAC__BLURB_TOP_BIT_ONE); j++)
+							blurb <<= 1;
+						msbs += j;
+
+						/* dispose of the unary end bit */
+						blurb <<= 1;
+						j++;
+						cbits += j;
+
+						uval = 0;
+						lsbs_left = parameter;
+						state++;
+						if(cbits == FLAC__BITS_PER_BLURB) {
+							cbits = 0;
+							CRC16_UPDATE_BLURB(bb, save_blurb, bb->read_crc16);
+							break;
+						}
+					}
+					else {
+						msbs += FLAC__BITS_PER_BLURB - cbits;
+						cbits = 0;
+						CRC16_UPDATE_BLURB(bb, save_blurb, bb->read_crc16);
+						break;
+					}
+				}
+				else {
+					const unsigned available_bits = FLAC__BITS_PER_BLURB - cbits;
+					if(lsbs_left >= available_bits) {
+						uval <<= available_bits;
+						uval |= (blurb >> cbits);
+						cbits = 0;
+						CRC16_UPDATE_BLURB(bb, save_blurb, bb->read_crc16);
+
+						if(lsbs_left == available_bits) {
+							/* compose the value */
+							uval |= (msbs << parameter);
+							if(uval & 1)
+								vals[val_i++] = -((int)(uval >> 1)) - 1;
+							else
+								vals[val_i++] = (int)(uval >> 1);
+							if(val_i == nvals)
+								break;
+
+							msbs = 0;
+							state = 0;
+						}
+
+						lsbs_left -= available_bits;
+						break;
+					}
+					else {
+						uval <<= lsbs_left;
+						uval |= (blurb >> (FLAC__BITS_PER_BLURB - lsbs_left));
+						blurb <<= lsbs_left;
+						cbits += lsbs_left;
+
+						/* compose the value */
+						uval |= (msbs << parameter);
+						if(uval & 1)
+							vals[val_i++] = -((int)(uval >> 1)) - 1;
+						else
+							vals[val_i++] = (int)(uval >> 1);
+						if(val_i == nvals) {
+							/* back up one if we exited the for loop because we read all nvals but the end came in the middle of a blurb */
+							i--;
+							break;
+						}
+
+						msbs = 0;
+						state = 0;
+					}
+				}
+			}
+		}
+		bb->consumed_blurbs = i;
+		bb->consumed_bits = cbits;
+		bb->total_consumed_bits = (i << FLAC__BITS_PER_BLURB_LOG2) | cbits;
+		if(val_i < nvals) {
+			if(!bitbuffer_read_from_client_(bb, read_callback, client_data))
+				return false;
+			/* these must be zero because we can only get here if we got to the end of the buffer */
+			FLAC__ASSERT(bb->consumed_blurbs == 0);
+			FLAC__ASSERT(bb->consumed_bits == 0);
+			i = 0;
+		}
+	}
+
+	return true;
+}
+
+#if 0 /* UNUSED */
+FLAC__bool FLAC__bitbuffer_read_golomb_signed(FLAC__BitBuffer *bb, int *val, unsigned parameter, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data)
+{
+	FLAC__uint32 lsbs = 0, msbs = 0;
+	unsigned bit, uval, k;
+
+	FLAC__ASSERT(0 != bb);
+	FLAC__ASSERT(0 != bb->buffer);
+
+	k = FLAC__bitmath_ilog2(parameter);
+
+	/* read the unary MSBs and end bit */
+	if(!FLAC__bitbuffer_read_unary_unsigned(bb, &msbs, read_callback, client_data))
+		return false;
+
+	/* read the binary LSBs */
+	if(!FLAC__bitbuffer_read_raw_uint32(bb, &lsbs, k, read_callback, client_data))
+		return false;
+
+	if(parameter == 1u<<k) {
+		/* compose the value */
+		uval = (msbs << k) | lsbs;
+	}
+	else {
+		unsigned d = (1 << (k+1)) - parameter;
+		if(lsbs >= d) {
+			if(!FLAC__bitbuffer_read_bit(bb, &bit, read_callback, client_data))
+				return false;
+			lsbs <<= 1;
+			lsbs |= bit;
+			lsbs -= d;
+		}
+		/* compose the value */
+		uval = msbs * parameter + lsbs;
+	}
+
+	/* unfold unsigned to signed */
+	if(uval & 1)
+		*val = -((int)(uval >> 1)) - 1;
+	else
+		*val = (int)(uval >> 1);
+
+	return true;
+}
+
+FLAC__bool FLAC__bitbuffer_read_golomb_unsigned(FLAC__BitBuffer *bb, unsigned *val, unsigned parameter, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data)
+{
+	FLAC__uint32 lsbs, msbs = 0;
+	unsigned bit, k;
+
+	FLAC__ASSERT(0 != bb);
+	FLAC__ASSERT(0 != bb->buffer);
+
+	k = FLAC__bitmath_ilog2(parameter);
+
+	/* read the unary MSBs and end bit */
+	if(!FLAC__bitbuffer_read_unary_unsigned(bb, &msbs, read_callback, client_data))
+		return false;
+
+	/* read the binary LSBs */
+	if(!FLAC__bitbuffer_read_raw_uint32(bb, &lsbs, k, read_callback, client_data))
+		return false;
+
+	if(parameter == 1u<<k) {
+		/* compose the value */
+		*val = (msbs << k) | lsbs;
+	}
+	else {
+		unsigned d = (1 << (k+1)) - parameter;
+		if(lsbs >= d) {
+			if(!FLAC__bitbuffer_read_bit(bb, &bit, read_callback, client_data))
+				return false;
+			lsbs <<= 1;
+			lsbs |= bit;
+			lsbs -= d;
+		}
+		/* compose the value */
+		*val = msbs * parameter + lsbs;
+	}
+
+	return true;
+}
+#endif /* UNUSED */
+
+/* on return, if *val == 0xffffffff then the utf-8 sequence was invalid, but the return value will be true */
+FLAC__bool FLAC__bitbuffer_read_utf8_uint32(FLAC__BitBuffer *bb, FLAC__uint32 *val, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data, FLAC__byte *raw, unsigned *rawlen)
+{
+	FLAC__uint32 v = 0;
+	FLAC__uint32 x;
+	unsigned i;
+
+	if(!FLAC__bitbuffer_read_raw_uint32(bb, &x, 8, read_callback, client_data))
+		return false;
+	if(raw)
+		raw[(*rawlen)++] = (FLAC__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 {
+		*val = 0xffffffff;
+		return true;
+	}
+	for( ; i; i--) {
+		if(!FLAC__bitbuffer_read_raw_uint32(bb, &x, 8, read_callback, client_data))
+			return false;
+		if(raw)
+			raw[(*rawlen)++] = (FLAC__byte)x;
+		if(!(x & 0x80) || (x & 0x40)) { /* 10xxxxxx */
+			*val = 0xffffffff;
+			return true;
+		}
+		v <<= 6;
+		v |= (x & 0x3F);
+	}
+	*val = v;
+	return true;
+}
+
+/* on return, if *val == 0xffffffffffffffff then the utf-8 sequence was invalid, but the return value will be true */
+FLAC__bool FLAC__bitbuffer_read_utf8_uint64(FLAC__BitBuffer *bb, FLAC__uint64 *val, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data, FLAC__byte *raw, unsigned *rawlen)
+{
+	FLAC__uint64 v = 0;
+	FLAC__uint32 x;
+	unsigned i;
+
+	if(!FLAC__bitbuffer_read_raw_uint32(bb, &x, 8, read_callback, client_data))
+		return false;
+	if(raw)
+		raw[(*rawlen)++] = (FLAC__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 {
+		*val = FLAC__U64L(0xffffffffffffffff);
+		return true;
+	}
+	for( ; i; i--) {
+		if(!FLAC__bitbuffer_read_raw_uint32(bb, &x, 8, read_callback, client_data))
+			return false;
+		if(raw)
+			raw[(*rawlen)++] = (FLAC__byte)x;
+		if(!(x & 0x80) || (x & 0x40)) { /* 10xxxxxx */
+			*val = FLAC__U64L(0xffffffffffffffff);
+			return true;
+		}
+		v <<= 6;
+		v |= (x & 0x3F);
+	}
+	*val = v;
+	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 blurbs=%u bits=%u total_bits=%u consumed: blurbs=%u, bits=%u, total_bits=%u\n", bb->capacity, bb->blurbs, bb->bits, bb->total_bits, bb->consumed_blurbs, bb->consumed_bits, bb->total_consumed_bits);
+
+		for(i = 0; i < bb->blurbs; i++) {
+			fprintf(out, "%08X: ", i);
+			for(j = 0; j < FLAC__BITS_PER_BLURB; j++)
+				if(i*FLAC__BITS_PER_BLURB+j < bb->total_consumed_bits)
+					fprintf(out, ".");
+				else
+					fprintf(out, "%01u", bb->buffer[i] & (1 << (FLAC__BITS_PER_BLURB-j-1)) ? 1:0);
+			fprintf(out, "\n");
+		}
+		if(bb->bits > 0) {
+			fprintf(out, "%08X: ", i);
+			for(j = 0; j < bb->bits; j++)
+				if(i*FLAC__BITS_PER_BLURB+j < bb->total_consumed_bits)
+					fprintf(out, ".");
+				else
+					fprintf(out, "%01u", bb->buffer[i] & (1 << (bb->bits-j-1)) ? 1:0);
+			fprintf(out, "\n");
+		}
+	}
+}
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/bitmath.c
@@ -1,0 +1,136 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001,2002,2003,2004  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "private/bitmath.h"
+#include "FLAC/assert.h"
+
+/* An example of what FLAC__bitmath_ilog2() computes:
+ *
+ * ilog2( 0) = assertion failure
+ * ilog2( 1) = 0
+ * ilog2( 2) = 1
+ * ilog2( 3) = 1
+ * ilog2( 4) = 2
+ * ilog2( 5) = 2
+ * ilog2( 6) = 2
+ * ilog2( 7) = 2
+ * ilog2( 8) = 3
+ * ilog2( 9) = 3
+ * ilog2(10) = 3
+ * ilog2(11) = 3
+ * ilog2(12) = 3
+ * ilog2(13) = 3
+ * ilog2(14) = 3
+ * ilog2(15) = 3
+ * ilog2(16) = 4
+ * ilog2(17) = 4
+ * ilog2(18) = 4
+ */
+unsigned FLAC__bitmath_ilog2(unsigned v)
+{
+	unsigned l = 0;
+	FLAC__ASSERT(v > 0);
+	while(v >>= 1)
+		l++;
+	return l;
+}
+
+/* An example of what FLAC__bitmath_silog2() computes:
+ *
+ * silog2(-10) = 5
+ * silog2(- 9) = 5
+ * silog2(- 8) = 4
+ * silog2(- 7) = 4
+ * silog2(- 6) = 4
+ * silog2(- 5) = 4
+ * silog2(- 4) = 3
+ * silog2(- 3) = 3
+ * silog2(- 2) = 2
+ * silog2(- 1) = 2
+ * silog2(  0) = 0
+ * silog2(  1) = 2
+ * silog2(  2) = 3
+ * silog2(  3) = 3
+ * silog2(  4) = 4
+ * silog2(  5) = 4
+ * silog2(  6) = 4
+ * silog2(  7) = 4
+ * silog2(  8) = 5
+ * silog2(  9) = 5
+ * silog2( 10) = 5
+ */
+unsigned FLAC__bitmath_silog2(int v)
+{
+	while(1) {
+		if(v == 0) {
+			return 0;
+		}
+		else if(v > 0) {
+			unsigned l = 0;
+			while(v) {
+				l++;
+				v >>= 1;
+			}
+			return l+1;
+		}
+		else if(v == -1) {
+			return 2;
+		}
+		else {
+			v++;
+			v = -v;
+		}
+	}
+}
+
+unsigned FLAC__bitmath_silog2_wide(FLAC__int64 v)
+{
+	while(1) {
+		if(v == 0) {
+			return 0;
+		}
+		else if(v > 0) {
+			unsigned l = 0;
+			while(v) {
+				l++;
+				v >>= 1;
+			}
+			return l+1;
+		}
+		else if(v == -1) {
+			return 2;
+		}
+		else {
+			v++;
+			v = -v;
+		}
+	}
+}
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/cpu.c
@@ -1,0 +1,117 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001,2002,2003,2004  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "private/cpu.h"
+#include<stdlib.h>
+#include<stdio.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#if defined FLAC__CPU_PPC
+#if !defined FLAC__NO_ASM
+#if defined __APPLE__ && defined __MACH__
+#include <sys/sysctl.h>
+#endif /* __APPLE__ && __MACH__ */
+#endif /* FLAC__NO_ASM */
+#endif /* FLAC__CPU_PPC */
+
+const unsigned FLAC__CPUINFO_IA32_CPUID_CMOV = 0x00008000;
+const unsigned FLAC__CPUINFO_IA32_CPUID_MMX = 0x00800000;
+const unsigned FLAC__CPUINFO_IA32_CPUID_FXSR = 0x01000000;
+const unsigned FLAC__CPUINFO_IA32_CPUID_SSE = 0x02000000;
+const unsigned FLAC__CPUINFO_IA32_CPUID_SSE2 = 0x04000000;
+
+const unsigned FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_3DNOW = 0x80000000;
+const unsigned FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_EXT3DNOW = 0x40000000;
+const unsigned FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_EXTMMX = 0x00400000;
+
+
+void FLAC__cpu_info(FLAC__CPUInfo *info)
+{
+#ifdef FLAC__CPU_IA32
+	info->type = FLAC__CPUINFO_TYPE_IA32;
+#if !defined FLAC__NO_ASM && defined FLAC__HAS_NASM
+	info->use_asm = true;
+	{
+		unsigned cpuid = FLAC__cpu_info_asm_ia32();
+		info->data.ia32.cmov = (cpuid & FLAC__CPUINFO_IA32_CPUID_CMOV)? true : false;
+		info->data.ia32.mmx = (cpuid & FLAC__CPUINFO_IA32_CPUID_MMX)? true : false;
+		info->data.ia32.fxsr = (cpuid & FLAC__CPUINFO_IA32_CPUID_FXSR)? true : false;
+		info->data.ia32.sse = (cpuid & FLAC__CPUINFO_IA32_CPUID_SSE)? true : false;
+		info->data.ia32.sse2 = (cpuid & FLAC__CPUINFO_IA32_CPUID_SSE2)? true : false;
+
+#ifndef FLAC__SSE_OS
+		info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = false;
+#endif
+
+#ifdef FLAC__USE_3DNOW
+		cpuid = FLAC__cpu_info_extended_amd_asm_ia32();
+		info->data.ia32._3dnow = (cpuid & FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_3DNOW)? true : false;
+		info->data.ia32.ext3dnow = (cpuid & FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_EXT3DNOW)? true : false;
+		info->data.ia32.extmmx = (cpuid & FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_EXTMMX)? true : false;
+#else
+		info->data.ia32._3dnow = info->data.ia32.ext3dnow = info->data.ia32.extmmx = false;
+#endif
+	}
+#else
+	info->use_asm = false;
+#endif
+#elif defined FLAC__CPU_PPC
+	info->type = FLAC__CPUINFO_TYPE_PPC;
+#if !defined FLAC__NO_ASM
+	info->use_asm = true;
+#ifdef FLAC__USE_ALTIVEC
+#if defined __APPLE__ && defined __MACH__
+	{
+		int selectors[2] = { CTL_HW, HW_VECTORUNIT };
+		int result = 0;
+		size_t length = sizeof(result);
+		int error = sysctl(selectors, 2, &result, &length, 0, 0);
+
+		info->data.ppc.altivec = error==0 ? result!=0 : 0;
+	}
+#else /* __APPLE__ && __MACH__ */
+	/* don't know of any other thread-safe way to check */
+	info->data.ppc.altivec = 0;
+#endif /* __APPLE__ && __MACH__ */
+#else /* FLAC__USE_ALTIVEC */
+	info->data.ppc.altivec = 0;
+#endif /* FLAC__USE_ALTIVEC */
+#else /* FLAC__NO_ASM */
+	info->use_asm = false;
+#endif /* FLAC__NO_ASM */
+#else
+	info->type = FLAC__CPUINFO_TYPE_UNKNOWN;
+	info->use_asm = false;
+#endif
+}
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/crc.c
@@ -1,0 +1,149 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "private/crc.h"
+
+/* CRC-8, poly = x^8 + x^2 + x^1 + x^0, init = 0 */
+
+FLAC__byte const FLAC__crc8_table[256] = {
+	0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15,
+	0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,
+	0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65,
+	0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D,
+	0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5,
+	0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,
+	0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85,
+	0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD,
+	0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2,
+	0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA,
+	0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2,
+	0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,
+	0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32,
+	0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A,
+	0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42,
+	0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A,
+	0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C,
+	0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,
+	0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC,
+	0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4,
+	0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C,
+	0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44,
+	0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C,
+	0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,
+	0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B,
+	0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63,
+	0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B,
+	0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13,
+	0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB,
+	0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,
+	0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB,
+	0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3
+};
+
+/* CRC-16, poly = x^16 + x^15 + x^2 + x^0, init = 0 */
+
+FLAC__uint16 FLAC__crc16_table[256] = {
+	0x0000,  0x8005,  0x800f,  0x000a,  0x801b,  0x001e,  0x0014,  0x8011,
+	0x8033,  0x0036,  0x003c,  0x8039,  0x0028,  0x802d,  0x8027,  0x0022,
+	0x8063,  0x0066,  0x006c,  0x8069,  0x0078,  0x807d,  0x8077,  0x0072,
+	0x0050,  0x8055,  0x805f,  0x005a,  0x804b,  0x004e,  0x0044,  0x8041,
+	0x80c3,  0x00c6,  0x00cc,  0x80c9,  0x00d8,  0x80dd,  0x80d7,  0x00d2,
+	0x00f0,  0x80f5,  0x80ff,  0x00fa,  0x80eb,  0x00ee,  0x00e4,  0x80e1,
+	0x00a0,  0x80a5,  0x80af,  0x00aa,  0x80bb,  0x00be,  0x00b4,  0x80b1,
+	0x8093,  0x0096,  0x009c,  0x8099,  0x0088,  0x808d,  0x8087,  0x0082,
+	0x8183,  0x0186,  0x018c,  0x8189,  0x0198,  0x819d,  0x8197,  0x0192,
+	0x01b0,  0x81b5,  0x81bf,  0x01ba,  0x81ab,  0x01ae,  0x01a4,  0x81a1,
+	0x01e0,  0x81e5,  0x81ef,  0x01ea,  0x81fb,  0x01fe,  0x01f4,  0x81f1,
+	0x81d3,  0x01d6,  0x01dc,  0x81d9,  0x01c8,  0x81cd,  0x81c7,  0x01c2,
+	0x0140,  0x8145,  0x814f,  0x014a,  0x815b,  0x015e,  0x0154,  0x8151,
+	0x8173,  0x0176,  0x017c,  0x8179,  0x0168,  0x816d,  0x8167,  0x0162,
+	0x8123,  0x0126,  0x012c,  0x8129,  0x0138,  0x813d,  0x8137,  0x0132,
+	0x0110,  0x8115,  0x811f,  0x011a,  0x810b,  0x010e,  0x0104,  0x8101,
+	0x8303,  0x0306,  0x030c,  0x8309,  0x0318,  0x831d,  0x8317,  0x0312,
+	0x0330,  0x8335,  0x833f,  0x033a,  0x832b,  0x032e,  0x0324,  0x8321,
+	0x0360,  0x8365,  0x836f,  0x036a,  0x837b,  0x037e,  0x0374,  0x8371,
+	0x8353,  0x0356,  0x035c,  0x8359,  0x0348,  0x834d,  0x8347,  0x0342,
+	0x03c0,  0x83c5,  0x83cf,  0x03ca,  0x83db,  0x03de,  0x03d4,  0x83d1,
+	0x83f3,  0x03f6,  0x03fc,  0x83f9,  0x03e8,  0x83ed,  0x83e7,  0x03e2,
+	0x83a3,  0x03a6,  0x03ac,  0x83a9,  0x03b8,  0x83bd,  0x83b7,  0x03b2,
+	0x0390,  0x8395,  0x839f,  0x039a,  0x838b,  0x038e,  0x0384,  0x8381,
+	0x0280,  0x8285,  0x828f,  0x028a,  0x829b,  0x029e,  0x0294,  0x8291,
+	0x82b3,  0x02b6,  0x02bc,  0x82b9,  0x02a8,  0x82ad,  0x82a7,  0x02a2,
+	0x82e3,  0x02e6,  0x02ec,  0x82e9,  0x02f8,  0x82fd,  0x82f7,  0x02f2,
+	0x02d0,  0x82d5,  0x82df,  0x02da,  0x82cb,  0x02ce,  0x02c4,  0x82c1,
+	0x8243,  0x0246,  0x024c,  0x8249,  0x0258,  0x825d,  0x8257,  0x0252,
+	0x0270,  0x8275,  0x827f,  0x027a,  0x826b,  0x026e,  0x0264,  0x8261,
+	0x0220,  0x8225,  0x822f,  0x022a,  0x823b,  0x023e,  0x0234,  0x8231,
+	0x8213,  0x0216,  0x021c,  0x8219,  0x0208,  0x820d,  0x8207,  0x0202
+};
+
+
+void FLAC__crc8_update(const FLAC__byte data, FLAC__uint8 *crc)
+{
+	*crc = FLAC__crc8_table[*crc ^ data];
+}
+
+void FLAC__crc8_update_block(const FLAC__byte *data, unsigned len, FLAC__uint8 *crc)
+{
+	while(len--)
+		*crc = FLAC__crc8_table[*crc ^ *data++];
+}
+
+FLAC__uint8 FLAC__crc8(const FLAC__byte *data, unsigned len)
+{
+	FLAC__uint8 crc = 0;
+
+	while(len--)
+		crc = FLAC__crc8_table[crc ^ *data++];
+
+	return crc;
+}
+
+void FLAC__crc16_update(const FLAC__byte data, FLAC__uint16 *crc)
+{
+	*crc = (*crc<<8) ^ FLAC__crc16_table[(*crc>>8) ^ data];
+}
+
+void FLAC__crc16_update_block(const FLAC__byte *data, unsigned len, FLAC__uint16 *crc)
+{
+	while(len--)
+		*crc = (*crc<<8) ^ FLAC__crc16_table[(*crc>>8) ^ *data++];
+}
+
+FLAC__uint16 FLAC__crc16(const FLAC__byte *data, unsigned len)
+{
+	FLAC__uint16 crc = 0;
+
+	while(len--)
+		crc = (crc<<8) ^ FLAC__crc16_table[(crc>>8) ^ *data++];
+
+	return crc;
+}
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/file_decoder.c
@@ -1,0 +1,673 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h> /* for malloc() */
+#include <string.h> /* for strcmp() */
+#include <sys/stat.h> /* for stat() */
+#if defined _MSC_VER || defined __MINGW32__
+#include <io.h> /* for _setmode() */
+#include <fcntl.h> /* for _O_BINARY */
+#elif defined __CYGWIN__
+#include <io.h> /* for setmode(), O_BINARY */
+#include <fcntl.h> /* for _O_BINARY */
+#endif
+#include "FLAC/assert.h"
+#include "protected/file_decoder.h"
+#include "protected/seekable_stream_decoder.h"
+
+/***********************************************************************
+ *
+ * Private class method prototypes
+ *
+ ***********************************************************************/
+
+static void set_defaults_(FLAC__FileDecoder *decoder);
+static FILE *get_binary_stdin_();
+static FLAC__SeekableStreamDecoderReadStatus read_callback_(const FLAC__SeekableStreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data);
+static FLAC__SeekableStreamDecoderSeekStatus seek_callback_(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data);
+static FLAC__SeekableStreamDecoderTellStatus tell_callback_(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data);
+static FLAC__SeekableStreamDecoderLengthStatus length_callback_(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data);
+static FLAC__bool eof_callback_(const FLAC__SeekableStreamDecoder *decoder, void *client_data);
+static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__SeekableStreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data);
+static void metadata_callback_(const FLAC__SeekableStreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data);
+static void error_callback_(const FLAC__SeekableStreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
+
+/***********************************************************************
+ *
+ * Private class data
+ *
+ ***********************************************************************/
+
+typedef struct FLAC__FileDecoderPrivate {
+	FLAC__FileDecoderWriteCallback write_callback;
+	FLAC__FileDecoderMetadataCallback metadata_callback;
+	FLAC__FileDecoderErrorCallback error_callback;
+	void *client_data;
+	FILE *file;
+	char *filename; /* == NULL if stdin */
+	FLAC__SeekableStreamDecoder *seekable_stream_decoder;
+} FLAC__FileDecoderPrivate;
+
+/***********************************************************************
+ *
+ * Public static class data
+ *
+ ***********************************************************************/
+
+FLAC_API const char * const FLAC__FileDecoderStateString[] = {
+	"FLAC__FILE_DECODER_OK",
+	"FLAC__FILE_DECODER_END_OF_FILE",
+	"FLAC__FILE_DECODER_ERROR_OPENING_FILE",
+	"FLAC__FILE_DECODER_MEMORY_ALLOCATION_ERROR",
+	"FLAC__FILE_DECODER_SEEK_ERROR",
+	"FLAC__FILE_DECODER_SEEKABLE_STREAM_DECODER_ERROR",
+	"FLAC__FILE_DECODER_ALREADY_INITIALIZED",
+	"FLAC__FILE_DECODER_INVALID_CALLBACK",
+	"FLAC__FILE_DECODER_UNINITIALIZED"
+};
+
+/***********************************************************************
+ *
+ * Class constructor/destructor
+ *
+ ***********************************************************************/
+
+FLAC_API FLAC__FileDecoder *FLAC__file_decoder_new()
+{
+	FLAC__FileDecoder *decoder;
+
+	FLAC__ASSERT(sizeof(int) >= 4); /* we want to die right away if this is not true */
+
+	decoder = (FLAC__FileDecoder*)calloc(1, sizeof(FLAC__FileDecoder));
+	if(decoder == 0) {
+		return 0;
+	}
+
+	decoder->protected_ = (FLAC__FileDecoderProtected*)calloc(1, sizeof(FLAC__FileDecoderProtected));
+	if(decoder->protected_ == 0) {
+		free(decoder);
+		return 0;
+	}
+
+	decoder->private_ = (FLAC__FileDecoderPrivate*)calloc(1, sizeof(FLAC__FileDecoderPrivate));
+	if(decoder->private_ == 0) {
+		free(decoder->protected_);
+		free(decoder);
+		return 0;
+	}
+
+	decoder->private_->seekable_stream_decoder = FLAC__seekable_stream_decoder_new();
+	if(0 == decoder->private_->seekable_stream_decoder) {
+		free(decoder->private_);
+		free(decoder->protected_);
+		free(decoder);
+		return 0;
+	}
+
+	decoder->private_->file = 0;
+
+	set_defaults_(decoder);
+
+	decoder->protected_->state = FLAC__FILE_DECODER_UNINITIALIZED;
+
+	return decoder;
+}
+
+FLAC_API void FLAC__file_decoder_delete(FLAC__FileDecoder *decoder)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->protected_);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->private_->seekable_stream_decoder);
+
+	(void)FLAC__file_decoder_finish(decoder);
+
+	FLAC__seekable_stream_decoder_delete(decoder->private_->seekable_stream_decoder);
+
+	free(decoder->private_);
+	free(decoder->protected_);
+	free(decoder);
+}
+
+/***********************************************************************
+ *
+ * Public class methods
+ *
+ ***********************************************************************/
+
+FLAC_API FLAC__FileDecoderState FLAC__file_decoder_init(FLAC__FileDecoder *decoder)
+{
+	FLAC__ASSERT(0 != decoder);
+
+	if(decoder->protected_->state != FLAC__FILE_DECODER_UNINITIALIZED)
+		return decoder->protected_->state = FLAC__FILE_DECODER_ALREADY_INITIALIZED;
+
+	if(0 == decoder->private_->write_callback || 0 == decoder->private_->metadata_callback || 0 == decoder->private_->error_callback)
+		return decoder->protected_->state = FLAC__FILE_DECODER_INVALID_CALLBACK;
+
+	if(0 == decoder->private_->filename)
+		decoder->private_->file = get_binary_stdin_();
+	else
+		decoder->private_->file = fopen(decoder->private_->filename, "rb");
+
+	if(decoder->private_->file == 0)
+		return decoder->protected_->state = FLAC__FILE_DECODER_ERROR_OPENING_FILE;
+
+	FLAC__seekable_stream_decoder_set_read_callback(decoder->private_->seekable_stream_decoder, read_callback_);
+	FLAC__seekable_stream_decoder_set_seek_callback(decoder->private_->seekable_stream_decoder, seek_callback_);
+	FLAC__seekable_stream_decoder_set_tell_callback(decoder->private_->seekable_stream_decoder, tell_callback_);
+	FLAC__seekable_stream_decoder_set_length_callback(decoder->private_->seekable_stream_decoder, length_callback_);
+	FLAC__seekable_stream_decoder_set_eof_callback(decoder->private_->seekable_stream_decoder, eof_callback_);
+	FLAC__seekable_stream_decoder_set_write_callback(decoder->private_->seekable_stream_decoder, write_callback_);
+	FLAC__seekable_stream_decoder_set_metadata_callback(decoder->private_->seekable_stream_decoder, metadata_callback_);
+	FLAC__seekable_stream_decoder_set_error_callback(decoder->private_->seekable_stream_decoder, error_callback_);
+	FLAC__seekable_stream_decoder_set_client_data(decoder->private_->seekable_stream_decoder, decoder);
+
+	if(FLAC__seekable_stream_decoder_init(decoder->private_->seekable_stream_decoder) != FLAC__SEEKABLE_STREAM_DECODER_OK)
+		return decoder->protected_->state = FLAC__FILE_DECODER_SEEKABLE_STREAM_DECODER_ERROR;
+
+	return decoder->protected_->state = FLAC__FILE_DECODER_OK;
+}
+
+FLAC_API FLAC__bool FLAC__file_decoder_finish(FLAC__FileDecoder *decoder)
+{
+	FLAC__ASSERT(0 != decoder);
+
+	if(decoder->protected_->state == FLAC__FILE_DECODER_UNINITIALIZED)
+		return true;
+
+	FLAC__ASSERT(0 != decoder->private_->seekable_stream_decoder);
+
+	if(0 != decoder->private_->file && decoder->private_->file != stdin) {
+		fclose(decoder->private_->file);
+		decoder->private_->file = 0;
+	}
+
+	if(0 != decoder->private_->filename) {
+		free(decoder->private_->filename);
+		decoder->private_->filename = 0;
+	}
+
+	set_defaults_(decoder);
+
+	decoder->protected_->state = FLAC__FILE_DECODER_UNINITIALIZED;
+
+	return FLAC__seekable_stream_decoder_finish(decoder->private_->seekable_stream_decoder);
+}
+
+FLAC_API FLAC__bool FLAC__file_decoder_set_md5_checking(FLAC__FileDecoder *decoder, FLAC__bool value)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->protected_);
+	FLAC__ASSERT(0 != decoder->private_->seekable_stream_decoder);
+	if(decoder->protected_->state != FLAC__FILE_DECODER_UNINITIALIZED)
+		return false;
+	return FLAC__seekable_stream_decoder_set_md5_checking(decoder->private_->seekable_stream_decoder, value);
+}
+
+FLAC_API FLAC__bool FLAC__file_decoder_set_filename(FLAC__FileDecoder *decoder, const char *value)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->protected_);
+	FLAC__ASSERT(0 != value);
+	if(decoder->protected_->state != FLAC__FILE_DECODER_UNINITIALIZED)
+		return false;
+	if(0 != decoder->private_->filename) {
+		free(decoder->private_->filename);
+		decoder->private_->filename = 0;
+	}
+	if(0 != strcmp(value, "-")) {
+		if(0 == (decoder->private_->filename = (char*)malloc(strlen(value)+1))) {
+			decoder->protected_->state = FLAC__FILE_DECODER_MEMORY_ALLOCATION_ERROR;
+			return false;
+		}
+		strcpy(decoder->private_->filename, value);
+	}
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__file_decoder_set_write_callback(FLAC__FileDecoder *decoder, FLAC__FileDecoderWriteCallback value)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->protected_);
+	if(decoder->protected_->state != FLAC__FILE_DECODER_UNINITIALIZED)
+		return false;
+	decoder->private_->write_callback = value;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__file_decoder_set_metadata_callback(FLAC__FileDecoder *decoder, FLAC__FileDecoderMetadataCallback value)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->protected_);
+	if(decoder->protected_->state != FLAC__FILE_DECODER_UNINITIALIZED)
+		return false;
+	decoder->private_->metadata_callback = value;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__file_decoder_set_error_callback(FLAC__FileDecoder *decoder, FLAC__FileDecoderErrorCallback value)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->protected_);
+	if(decoder->protected_->state != FLAC__FILE_DECODER_UNINITIALIZED)
+		return false;
+	decoder->private_->error_callback = value;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__file_decoder_set_client_data(FLAC__FileDecoder *decoder, void *value)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->protected_);
+	if(decoder->protected_->state != FLAC__FILE_DECODER_UNINITIALIZED)
+		return false;
+	decoder->private_->client_data = value;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__file_decoder_set_metadata_respond(FLAC__FileDecoder *decoder, FLAC__MetadataType type)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->protected_);
+	FLAC__ASSERT(0 != decoder->private_->seekable_stream_decoder);
+	if(decoder->protected_->state != FLAC__FILE_DECODER_UNINITIALIZED)
+		return false;
+	return FLAC__seekable_stream_decoder_set_metadata_respond(decoder->private_->seekable_stream_decoder, type);
+}
+
+FLAC_API FLAC__bool FLAC__file_decoder_set_metadata_respond_application(FLAC__FileDecoder *decoder, const FLAC__byte id[4])
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->protected_);
+	FLAC__ASSERT(0 != decoder->private_->seekable_stream_decoder);
+	if(decoder->protected_->state != FLAC__FILE_DECODER_UNINITIALIZED)
+		return false;
+	return FLAC__seekable_stream_decoder_set_metadata_respond_application(decoder->private_->seekable_stream_decoder, id);
+}
+
+FLAC_API FLAC__bool FLAC__file_decoder_set_metadata_respond_all(FLAC__FileDecoder *decoder)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->protected_);
+	FLAC__ASSERT(0 != decoder->private_->seekable_stream_decoder);
+	if(decoder->protected_->state != FLAC__FILE_DECODER_UNINITIALIZED)
+		return false;
+	return FLAC__seekable_stream_decoder_set_metadata_respond_all(decoder->private_->seekable_stream_decoder);
+}
+
+FLAC_API FLAC__bool FLAC__file_decoder_set_metadata_ignore(FLAC__FileDecoder *decoder, FLAC__MetadataType type)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->protected_);
+	FLAC__ASSERT(0 != decoder->private_->seekable_stream_decoder);
+	if(decoder->protected_->state != FLAC__FILE_DECODER_UNINITIALIZED)
+		return false;
+	return FLAC__seekable_stream_decoder_set_metadata_ignore(decoder->private_->seekable_stream_decoder, type);
+}
+
+FLAC_API FLAC__bool FLAC__file_decoder_set_metadata_ignore_application(FLAC__FileDecoder *decoder, const FLAC__byte id[4])
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->protected_);
+	FLAC__ASSERT(0 != decoder->private_->seekable_stream_decoder);
+	if(decoder->protected_->state != FLAC__FILE_DECODER_UNINITIALIZED)
+		return false;
+	return FLAC__seekable_stream_decoder_set_metadata_ignore_application(decoder->private_->seekable_stream_decoder, id);
+}
+
+FLAC_API FLAC__bool FLAC__file_decoder_set_metadata_ignore_all(FLAC__FileDecoder *decoder)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->protected_);
+	FLAC__ASSERT(0 != decoder->private_->seekable_stream_decoder);
+	if(decoder->protected_->state != FLAC__FILE_DECODER_UNINITIALIZED)
+		return false;
+	return FLAC__seekable_stream_decoder_set_metadata_ignore_all(decoder->private_->seekable_stream_decoder);
+}
+
+FLAC_API FLAC__FileDecoderState FLAC__file_decoder_get_state(const FLAC__FileDecoder *decoder)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->protected_);
+	return decoder->protected_->state;
+}
+
+FLAC_API FLAC__SeekableStreamDecoderState FLAC__file_decoder_get_seekable_stream_decoder_state(const FLAC__FileDecoder *decoder)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	return FLAC__seekable_stream_decoder_get_state(decoder->private_->seekable_stream_decoder);
+}
+
+FLAC_API FLAC__StreamDecoderState FLAC__file_decoder_get_stream_decoder_state(const FLAC__FileDecoder *decoder)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	return FLAC__seekable_stream_decoder_get_stream_decoder_state(decoder->private_->seekable_stream_decoder);
+}
+
+FLAC_API const char *FLAC__file_decoder_get_resolved_state_string(const FLAC__FileDecoder *decoder)
+{
+	if(decoder->protected_->state != FLAC__FILE_DECODER_SEEKABLE_STREAM_DECODER_ERROR)
+		return FLAC__FileDecoderStateString[decoder->protected_->state];
+	else
+		return FLAC__seekable_stream_decoder_get_resolved_state_string(decoder->private_->seekable_stream_decoder);
+}
+
+FLAC_API FLAC__bool FLAC__file_decoder_get_md5_checking(const FLAC__FileDecoder *decoder)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	return FLAC__seekable_stream_decoder_get_md5_checking(decoder->private_->seekable_stream_decoder);
+}
+
+FLAC_API unsigned FLAC__file_decoder_get_channels(const FLAC__FileDecoder *decoder)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	return FLAC__seekable_stream_decoder_get_channels(decoder->private_->seekable_stream_decoder);
+}
+
+FLAC_API FLAC__ChannelAssignment FLAC__file_decoder_get_channel_assignment(const FLAC__FileDecoder *decoder)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	return FLAC__seekable_stream_decoder_get_channel_assignment(decoder->private_->seekable_stream_decoder);
+}
+
+FLAC_API unsigned FLAC__file_decoder_get_bits_per_sample(const FLAC__FileDecoder *decoder)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	return FLAC__seekable_stream_decoder_get_bits_per_sample(decoder->private_->seekable_stream_decoder);
+}
+
+FLAC_API unsigned FLAC__file_decoder_get_sample_rate(const FLAC__FileDecoder *decoder)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	return FLAC__seekable_stream_decoder_get_sample_rate(decoder->private_->seekable_stream_decoder);
+}
+
+FLAC_API unsigned FLAC__file_decoder_get_blocksize(const FLAC__FileDecoder *decoder)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	return FLAC__seekable_stream_decoder_get_blocksize(decoder->private_->seekable_stream_decoder);
+}
+
+FLAC_API FLAC__bool FLAC__file_decoder_get_decode_position(const FLAC__FileDecoder *decoder, FLAC__uint64 *position)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	return FLAC__seekable_stream_decoder_get_decode_position(decoder->private_->seekable_stream_decoder, position);
+}
+
+FLAC_API FLAC__bool FLAC__file_decoder_process_single(FLAC__FileDecoder *decoder)
+{
+	FLAC__bool ret;
+	FLAC__ASSERT(0 != decoder);
+
+	if(decoder->private_->seekable_stream_decoder->protected_->state == FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM)
+		decoder->protected_->state = FLAC__FILE_DECODER_END_OF_FILE;
+
+	if(decoder->protected_->state == FLAC__FILE_DECODER_END_OF_FILE)
+		return true;
+
+	FLAC__ASSERT(decoder->protected_->state == FLAC__FILE_DECODER_OK);
+
+	ret = FLAC__seekable_stream_decoder_process_single(decoder->private_->seekable_stream_decoder);
+	if(!ret)
+		decoder->protected_->state = FLAC__FILE_DECODER_SEEKABLE_STREAM_DECODER_ERROR;
+
+	return ret;
+}
+
+FLAC_API FLAC__bool FLAC__file_decoder_process_until_end_of_metadata(FLAC__FileDecoder *decoder)
+{
+	FLAC__bool ret;
+	FLAC__ASSERT(0 != decoder);
+
+	if(decoder->private_->seekable_stream_decoder->protected_->state == FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM)
+		decoder->protected_->state = FLAC__FILE_DECODER_END_OF_FILE;
+
+	if(decoder->protected_->state == FLAC__FILE_DECODER_END_OF_FILE)
+		return true;
+
+	FLAC__ASSERT(decoder->protected_->state == FLAC__FILE_DECODER_OK);
+
+	ret = FLAC__seekable_stream_decoder_process_until_end_of_metadata(decoder->private_->seekable_stream_decoder);
+	if(!ret)
+		decoder->protected_->state = FLAC__FILE_DECODER_SEEKABLE_STREAM_DECODER_ERROR;
+
+	return ret;
+}
+
+FLAC_API FLAC__bool FLAC__file_decoder_process_until_end_of_file(FLAC__FileDecoder *decoder)
+{
+	FLAC__bool ret;
+	FLAC__ASSERT(0 != decoder);
+
+	if(decoder->private_->seekable_stream_decoder->protected_->state == FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM)
+		decoder->protected_->state = FLAC__FILE_DECODER_END_OF_FILE;
+
+	if(decoder->protected_->state == FLAC__FILE_DECODER_END_OF_FILE)
+		return true;
+
+	FLAC__ASSERT(decoder->protected_->state == FLAC__FILE_DECODER_OK);
+
+	ret = FLAC__seekable_stream_decoder_process_until_end_of_stream(decoder->private_->seekable_stream_decoder);
+	if(!ret)
+		decoder->protected_->state = FLAC__FILE_DECODER_SEEKABLE_STREAM_DECODER_ERROR;
+
+	return ret;
+}
+
+FLAC_API FLAC__bool FLAC__file_decoder_skip_single_frame(FLAC__FileDecoder *decoder)
+{
+	FLAC__bool ret;
+	FLAC__ASSERT(0 != decoder);
+
+	if(decoder->private_->seekable_stream_decoder->protected_->state == FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM)
+		decoder->protected_->state = FLAC__FILE_DECODER_END_OF_FILE;
+
+	if(decoder->protected_->state == FLAC__FILE_DECODER_END_OF_FILE)
+		return true;
+
+	FLAC__ASSERT(decoder->protected_->state == FLAC__FILE_DECODER_OK);
+
+	ret = FLAC__seekable_stream_decoder_skip_single_frame(decoder->private_->seekable_stream_decoder);
+	if(!ret)
+		decoder->protected_->state = FLAC__FILE_DECODER_SEEKABLE_STREAM_DECODER_ERROR;
+
+	return ret;
+}
+
+FLAC_API FLAC__bool FLAC__file_decoder_seek_absolute(FLAC__FileDecoder *decoder, FLAC__uint64 sample)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(decoder->protected_->state == FLAC__FILE_DECODER_OK || decoder->protected_->state == FLAC__FILE_DECODER_END_OF_FILE);
+
+	if(decoder->private_->filename == 0) { /* means the file is stdin... */
+		decoder->protected_->state = FLAC__FILE_DECODER_SEEK_ERROR;
+		return false;
+	}
+
+	if(!FLAC__seekable_stream_decoder_seek_absolute(decoder->private_->seekable_stream_decoder, sample)) {
+		decoder->protected_->state = FLAC__FILE_DECODER_SEEK_ERROR;
+		return false;
+	}
+	else {
+		decoder->protected_->state = FLAC__FILE_DECODER_OK;
+		return true;
+	}
+}
+
+
+/***********************************************************************
+ *
+ * Private class methods
+ *
+ ***********************************************************************/
+
+void set_defaults_(FLAC__FileDecoder *decoder)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+
+	decoder->private_->filename = 0;
+	decoder->private_->write_callback = 0;
+	decoder->private_->metadata_callback = 0;
+	decoder->private_->error_callback = 0;
+	decoder->private_->client_data = 0;
+}
+
+/*
+ * This will forcibly set stdin to binary mode (for OSes that require it)
+ */
+FILE *get_binary_stdin_()
+{
+	/* if something breaks here it is probably due to the presence or
+	 * absence of an underscore before the identifiers 'setmode',
+	 * 'fileno', and/or 'O_BINARY'; check your system header files.
+	 */
+#if defined _MSC_VER || defined __MINGW32__
+	_setmode(_fileno(stdin), _O_BINARY);
+#elif defined __CYGWIN__
+	/* almost certainly not needed for any modern Cygwin, but let's be safe... */
+	setmode(_fileno(stdin), _O_BINARY);
+#endif
+
+	return stdin;
+}
+
+FLAC__SeekableStreamDecoderReadStatus read_callback_(const FLAC__SeekableStreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data)
+{
+	FLAC__FileDecoder *file_decoder = (FLAC__FileDecoder *)client_data;
+	(void)decoder;
+
+	if(*bytes > 0) {
+		*bytes = (unsigned)fread(buffer, sizeof(FLAC__byte), *bytes, file_decoder->private_->file);
+		if(ferror(file_decoder->private_->file)) {
+			return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_ERROR;
+		}
+		else {
+			return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK;
+		}
+	}
+	else
+		return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_ERROR; /* abort to avoid a deadlock */
+}
+
+FLAC__SeekableStreamDecoderSeekStatus seek_callback_(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data)
+{
+	FLAC__FileDecoder *file_decoder = (FLAC__FileDecoder *)client_data;
+	(void)decoder;
+
+	if(fseek(file_decoder->private_->file, (long)absolute_byte_offset, SEEK_SET) < 0)
+		return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR;
+	else
+		return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK;
+}
+
+FLAC__SeekableStreamDecoderTellStatus tell_callback_(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
+{
+	FLAC__FileDecoder *file_decoder = (FLAC__FileDecoder *)client_data;
+	long pos;
+	(void)decoder;
+
+	if((pos = ftell(file_decoder->private_->file)) < 0)
+		return FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_ERROR;
+	else {
+		*absolute_byte_offset = (FLAC__uint64)pos;
+		return FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK;
+	}
+}
+
+FLAC__SeekableStreamDecoderLengthStatus length_callback_(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data)
+{
+	FLAC__FileDecoder *file_decoder = (FLAC__FileDecoder *)client_data;
+	struct stat filestats;
+	(void)decoder;
+
+	if(0 == file_decoder->private_->filename || stat(file_decoder->private_->filename, &filestats) != 0)
+		return FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_ERROR;
+	else {
+		*stream_length = (FLAC__uint64)filestats.st_size;
+		return FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK;
+	}
+}
+
+FLAC__bool eof_callback_(const FLAC__SeekableStreamDecoder *decoder, void *client_data)
+{
+	FLAC__FileDecoder *file_decoder = (FLAC__FileDecoder *)client_data;
+	(void)decoder;
+
+	return feof(file_decoder->private_->file)? true : false;
+}
+
+FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__SeekableStreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
+{
+	FLAC__FileDecoder *file_decoder = (FLAC__FileDecoder *)client_data;
+	(void)decoder;
+
+	return file_decoder->private_->write_callback(file_decoder, frame, buffer, file_decoder->private_->client_data);
+}
+
+void metadata_callback_(const FLAC__SeekableStreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
+{
+	FLAC__FileDecoder *file_decoder = (FLAC__FileDecoder *)client_data;
+	(void)decoder;
+
+	file_decoder->private_->metadata_callback(file_decoder, metadata, file_decoder->private_->client_data);
+}
+
+void error_callback_(const FLAC__SeekableStreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+	FLAC__FileDecoder *file_decoder = (FLAC__FileDecoder *)client_data;
+	(void)decoder;
+
+	file_decoder->private_->error_callback(file_decoder, status, file_decoder->private_->client_data);
+}
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/file_encoder.c
@@ -1,0 +1,776 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2002,2003,2004  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h> /* for malloc() */
+#include <string.h> /* for strlen(), strcpy() */
+#include "FLAC/assert.h"
+#include "protected/file_encoder.h"
+
+#ifdef max
+#undef max
+#endif
+#define max(x,y) ((x)>(y)?(x):(y))
+
+/***********************************************************************
+ *
+ * Private class method prototypes
+ *
+ ***********************************************************************/
+
+/* unpublished debug routines */
+extern FLAC__bool FLAC__seekable_stream_encoder_disable_constant_subframes(FLAC__SeekableStreamEncoder *encoder, FLAC__bool value);
+extern FLAC__bool FLAC__seekable_stream_encoder_disable_fixed_subframes(FLAC__SeekableStreamEncoder *encoder, FLAC__bool value);
+extern FLAC__bool FLAC__seekable_stream_encoder_disable_verbatim_subframes(FLAC__SeekableStreamEncoder *encoder, FLAC__bool value);
+
+static void set_defaults_(FLAC__FileEncoder *encoder);
+static FLAC__SeekableStreamEncoderSeekStatus seek_callback_(const FLAC__SeekableStreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data);
+static FLAC__SeekableStreamEncoderTellStatus tell_callback_(const FLAC__SeekableStreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data);
+static FLAC__StreamEncoderWriteStatus write_callback_(const FLAC__SeekableStreamEncoder *encoder, const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data);
+
+/***********************************************************************
+ *
+ * Private class data
+ *
+ ***********************************************************************/
+
+typedef struct FLAC__FileEncoderPrivate {
+	FLAC__FileEncoderProgressCallback progress_callback;
+	void *client_data;
+	char *filename;
+	FLAC__uint64 bytes_written;
+	FLAC__uint64 samples_written;
+	unsigned frames_written;
+	unsigned total_frames_estimate;
+	FLAC__SeekableStreamEncoder *seekable_stream_encoder;
+	FILE *file;
+} FLAC__FileEncoderPrivate;
+
+/***********************************************************************
+ *
+ * Public static class data
+ *
+ ***********************************************************************/
+
+FLAC_API const char * const FLAC__FileEncoderStateString[] = {
+	"FLAC__FILE_ENCODER_OK",
+	"FLAC__FILE_ENCODER_NO_FILENAME",
+	"FLAC__FILE_ENCODER_SEEKABLE_STREAM_ENCODER_ERROR",
+	"FLAC__FILE_ENCODER_FATAL_ERROR_WHILE_WRITING",
+	"FLAC__FILE_ENCODER_ERROR_OPENING_FILE",
+	"FLAC__FILE_ENCODER_MEMORY_ALLOCATION_ERROR",
+	"FLAC__FILE_ENCODER_ALREADY_INITIALIZED",
+	"FLAC__FILE_ENCODER_UNINITIALIZED"
+};
+
+
+/***********************************************************************
+ *
+ * Class constructor/destructor
+ *
+ ***********************************************************************/
+
+FLAC_API FLAC__FileEncoder *FLAC__file_encoder_new()
+{
+	FLAC__FileEncoder *encoder;
+
+	FLAC__ASSERT(sizeof(int) >= 4); /* we want to die right away if this is not true */
+
+	encoder = (FLAC__FileEncoder*)calloc(1, sizeof(FLAC__FileEncoder));
+	if(encoder == 0) {
+		return 0;
+	}
+
+	encoder->protected_ = (FLAC__FileEncoderProtected*)calloc(1, sizeof(FLAC__FileEncoderProtected));
+	if(encoder->protected_ == 0) {
+		free(encoder);
+		return 0;
+	}
+
+	encoder->private_ = (FLAC__FileEncoderPrivate*)calloc(1, sizeof(FLAC__FileEncoderPrivate));
+	if(encoder->private_ == 0) {
+		free(encoder->protected_);
+		free(encoder);
+		return 0;
+	}
+
+	encoder->private_->seekable_stream_encoder = FLAC__seekable_stream_encoder_new();
+	if(0 == encoder->private_->seekable_stream_encoder) {
+		free(encoder->private_);
+		free(encoder->protected_);
+		free(encoder);
+		return 0;
+	}
+
+	encoder->private_->file = 0;
+
+	set_defaults_(encoder);
+
+	encoder->protected_->state = FLAC__FILE_ENCODER_UNINITIALIZED;
+
+	return encoder;
+}
+
+FLAC_API void FLAC__file_encoder_delete(FLAC__FileEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->protected_);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
+
+	(void)FLAC__file_encoder_finish(encoder);
+
+	FLAC__seekable_stream_encoder_delete(encoder->private_->seekable_stream_encoder);
+
+	free(encoder->private_);
+	free(encoder->protected_);
+	free(encoder);
+}
+
+/***********************************************************************
+ *
+ * Public class methods
+ *
+ ***********************************************************************/
+
+FLAC_API FLAC__FileEncoderState FLAC__file_encoder_init(FLAC__FileEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+
+	if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED)
+		return encoder->protected_->state = FLAC__FILE_ENCODER_ALREADY_INITIALIZED;
+
+	if(0 == encoder->private_->filename)
+		return encoder->protected_->state = FLAC__FILE_ENCODER_NO_FILENAME;
+
+	encoder->private_->file = fopen(encoder->private_->filename, "w+b");
+
+	if(encoder->private_->file == 0)
+		return encoder->protected_->state = FLAC__FILE_ENCODER_ERROR_OPENING_FILE;
+
+	encoder->private_->bytes_written = 0;
+	encoder->private_->samples_written = 0;
+	encoder->private_->frames_written = 0;
+
+	FLAC__seekable_stream_encoder_set_seek_callback(encoder->private_->seekable_stream_encoder, seek_callback_);
+	FLAC__seekable_stream_encoder_set_tell_callback(encoder->private_->seekable_stream_encoder, tell_callback_);
+	FLAC__seekable_stream_encoder_set_write_callback(encoder->private_->seekable_stream_encoder, write_callback_);
+	FLAC__seekable_stream_encoder_set_client_data(encoder->private_->seekable_stream_encoder, encoder);
+
+	if(FLAC__seekable_stream_encoder_init(encoder->private_->seekable_stream_encoder) != FLAC__SEEKABLE_STREAM_ENCODER_OK)
+		return encoder->protected_->state = FLAC__FILE_ENCODER_SEEKABLE_STREAM_ENCODER_ERROR;
+
+	{
+		unsigned blocksize = FLAC__file_encoder_get_blocksize(encoder);
+
+		FLAC__ASSERT(blocksize != 0);
+		encoder->private_->total_frames_estimate = (unsigned)((FLAC__file_encoder_get_total_samples_estimate(encoder) + blocksize - 1) / blocksize);
+	}
+
+	return encoder->protected_->state = FLAC__FILE_ENCODER_OK;
+}
+
+FLAC_API void FLAC__file_encoder_finish(FLAC__FileEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+
+	if(encoder->protected_->state == FLAC__FILE_ENCODER_UNINITIALIZED)
+		return;
+
+	FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
+
+	/* FLAC__seekable_stream_encoder_finish() might write data so we must close the file after it. */
+
+	FLAC__seekable_stream_encoder_finish(encoder->private_->seekable_stream_encoder);
+
+	if(0 != encoder->private_->file) {
+		fclose(encoder->private_->file);
+		encoder->private_->file = 0;
+	}
+
+	if(0 != encoder->private_->filename) {
+		free(encoder->private_->filename);
+		encoder->private_->filename = 0;
+	}
+
+	set_defaults_(encoder);
+
+	encoder->protected_->state = FLAC__FILE_ENCODER_UNINITIALIZED;
+}
+
+FLAC_API FLAC__bool FLAC__file_encoder_set_verify(FLAC__FileEncoder *encoder, FLAC__bool value)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
+	if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED)
+		return false;
+	return FLAC__seekable_stream_encoder_set_verify(encoder->private_->seekable_stream_encoder, value);
+}
+
+FLAC_API FLAC__bool FLAC__file_encoder_set_streamable_subset(FLAC__FileEncoder *encoder, FLAC__bool value)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
+	if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED)
+		return false;
+	return FLAC__seekable_stream_encoder_set_streamable_subset(encoder->private_->seekable_stream_encoder, value);
+}
+
+FLAC_API FLAC__bool FLAC__file_encoder_set_do_mid_side_stereo(FLAC__FileEncoder *encoder, FLAC__bool value)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
+	if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED)
+		return false;
+	return FLAC__seekable_stream_encoder_set_do_mid_side_stereo(encoder->private_->seekable_stream_encoder, value);
+}
+
+FLAC_API FLAC__bool FLAC__file_encoder_set_loose_mid_side_stereo(FLAC__FileEncoder *encoder, FLAC__bool value)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
+	if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED)
+		return false;
+	return FLAC__seekable_stream_encoder_set_loose_mid_side_stereo(encoder->private_->seekable_stream_encoder, value);
+}
+
+FLAC_API FLAC__bool FLAC__file_encoder_set_channels(FLAC__FileEncoder *encoder, unsigned value)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
+	if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED)
+		return false;
+	return FLAC__seekable_stream_encoder_set_channels(encoder->private_->seekable_stream_encoder, value);
+}
+
+FLAC_API FLAC__bool FLAC__file_encoder_set_bits_per_sample(FLAC__FileEncoder *encoder, unsigned value)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
+	if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED)
+		return false;
+	return FLAC__seekable_stream_encoder_set_bits_per_sample(encoder->private_->seekable_stream_encoder, value);
+}
+
+FLAC_API FLAC__bool FLAC__file_encoder_set_sample_rate(FLAC__FileEncoder *encoder, unsigned value)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
+	if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED)
+		return false;
+	return FLAC__seekable_stream_encoder_set_sample_rate(encoder->private_->seekable_stream_encoder, value);
+}
+
+FLAC_API FLAC__bool FLAC__file_encoder_set_blocksize(FLAC__FileEncoder *encoder, unsigned value)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
+	if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED)
+		return false;
+	return FLAC__seekable_stream_encoder_set_blocksize(encoder->private_->seekable_stream_encoder, value);
+}
+
+FLAC_API FLAC__bool FLAC__file_encoder_set_max_lpc_order(FLAC__FileEncoder *encoder, unsigned value)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
+	if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED)
+		return false;
+	return FLAC__seekable_stream_encoder_set_max_lpc_order(encoder->private_->seekable_stream_encoder, value);
+}
+
+FLAC_API FLAC__bool FLAC__file_encoder_set_qlp_coeff_precision(FLAC__FileEncoder *encoder, unsigned value)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
+	if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED)
+		return false;
+	return FLAC__seekable_stream_encoder_set_qlp_coeff_precision(encoder->private_->seekable_stream_encoder, value);
+}
+
+FLAC_API FLAC__bool FLAC__file_encoder_set_do_qlp_coeff_prec_search(FLAC__FileEncoder *encoder, FLAC__bool value)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
+	if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED)
+		return false;
+	return FLAC__seekable_stream_encoder_set_do_qlp_coeff_prec_search(encoder->private_->seekable_stream_encoder, value);
+}
+
+FLAC_API FLAC__bool FLAC__file_encoder_set_do_escape_coding(FLAC__FileEncoder *encoder, FLAC__bool value)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
+	if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED)
+		return false;
+	return FLAC__seekable_stream_encoder_set_do_escape_coding(encoder->private_->seekable_stream_encoder, value);
+}
+
+FLAC_API FLAC__bool FLAC__file_encoder_set_do_exhaustive_model_search(FLAC__FileEncoder *encoder, FLAC__bool value)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
+	if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED)
+		return false;
+	return FLAC__seekable_stream_encoder_set_do_exhaustive_model_search(encoder->private_->seekable_stream_encoder, value);
+}
+
+FLAC_API FLAC__bool FLAC__file_encoder_set_min_residual_partition_order(FLAC__FileEncoder *encoder, unsigned value)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
+	if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED)
+		return false;
+	return FLAC__seekable_stream_encoder_set_min_residual_partition_order(encoder->private_->seekable_stream_encoder, value);
+}
+
+FLAC_API FLAC__bool FLAC__file_encoder_set_max_residual_partition_order(FLAC__FileEncoder *encoder, unsigned value)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
+	if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED)
+		return false;
+	return FLAC__seekable_stream_encoder_set_max_residual_partition_order(encoder->private_->seekable_stream_encoder, value);
+}
+
+FLAC_API FLAC__bool FLAC__file_encoder_set_rice_parameter_search_dist(FLAC__FileEncoder *encoder, unsigned value)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
+	if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED)
+		return false;
+	return FLAC__seekable_stream_encoder_set_rice_parameter_search_dist(encoder->private_->seekable_stream_encoder, value);
+}
+
+FLAC_API FLAC__bool FLAC__file_encoder_set_total_samples_estimate(FLAC__FileEncoder *encoder, FLAC__uint64 value)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
+	if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED)
+		return false;
+	return FLAC__seekable_stream_encoder_set_total_samples_estimate(encoder->private_->seekable_stream_encoder, value);
+}
+
+FLAC_API FLAC__bool FLAC__file_encoder_set_metadata(FLAC__FileEncoder *encoder, FLAC__StreamMetadata **metadata, unsigned num_blocks)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
+	if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED)
+		return false;
+	return FLAC__seekable_stream_encoder_set_metadata(encoder->private_->seekable_stream_encoder, metadata, num_blocks);
+}
+
+FLAC_API FLAC__bool FLAC__file_encoder_set_filename(FLAC__FileEncoder *encoder, const char *value)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	FLAC__ASSERT(0 != value);
+	if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED)
+		return false;
+	if(0 != encoder->private_->filename) {
+		free(encoder->private_->filename);
+		encoder->private_->filename = 0;
+	}
+	if(0 == (encoder->private_->filename = (char*)malloc(strlen(value)+1))) {
+		encoder->protected_->state = FLAC__FILE_ENCODER_MEMORY_ALLOCATION_ERROR;
+		return false;
+	}
+	strcpy(encoder->private_->filename, value);
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__file_encoder_set_progress_callback(FLAC__FileEncoder *encoder, FLAC__FileEncoderProgressCallback value)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED)
+		return false;
+	encoder->private_->progress_callback = value;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__file_encoder_set_client_data(FLAC__FileEncoder *encoder, void *value)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED)
+		return false;
+	encoder->private_->client_data = value;
+	return true;
+}
+
+/*
+ * These three functions are not static, but not publically exposed in
+ * include/FLAC/ either.  They are used by the test suite.
+ */
+FLAC_API FLAC__bool FLAC__file_encoder_disable_constant_subframes(FLAC__FileEncoder *encoder, FLAC__bool value)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED)
+		return false;
+	return FLAC__seekable_stream_encoder_disable_constant_subframes(encoder->private_->seekable_stream_encoder, value);
+}
+
+FLAC_API FLAC__bool FLAC__file_encoder_disable_fixed_subframes(FLAC__FileEncoder *encoder, FLAC__bool value)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED)
+		return false;
+	return FLAC__seekable_stream_encoder_disable_fixed_subframes(encoder->private_->seekable_stream_encoder, value);
+}
+
+FLAC_API FLAC__bool FLAC__file_encoder_disable_verbatim_subframes(FLAC__FileEncoder *encoder, FLAC__bool value)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED)
+		return false;
+	return FLAC__seekable_stream_encoder_disable_verbatim_subframes(encoder->private_->seekable_stream_encoder, value);
+}
+
+FLAC_API FLAC__FileEncoderState FLAC__file_encoder_get_state(const FLAC__FileEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->protected_);
+	return encoder->protected_->state;
+}
+
+FLAC_API FLAC__SeekableStreamEncoderState FLAC__file_encoder_get_seekable_stream_encoder_state(const FLAC__FileEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	return FLAC__seekable_stream_encoder_get_state(encoder->private_->seekable_stream_encoder);
+}
+
+FLAC_API FLAC__StreamEncoderState FLAC__file_encoder_get_stream_encoder_state(const FLAC__FileEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	return FLAC__seekable_stream_encoder_get_stream_encoder_state(encoder->private_->seekable_stream_encoder);
+}
+
+FLAC_API FLAC__StreamDecoderState FLAC__file_encoder_get_verify_decoder_state(const FLAC__FileEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	return FLAC__seekable_stream_encoder_get_verify_decoder_state(encoder->private_->seekable_stream_encoder);
+}
+
+FLAC_API const char *FLAC__file_encoder_get_resolved_state_string(const FLAC__FileEncoder *encoder)
+{
+	if(encoder->protected_->state != FLAC__FILE_ENCODER_SEEKABLE_STREAM_ENCODER_ERROR)
+		return FLAC__FileEncoderStateString[encoder->protected_->state];
+	else
+		return FLAC__seekable_stream_encoder_get_resolved_state_string(encoder->private_->seekable_stream_encoder);
+}
+
+FLAC_API void FLAC__file_encoder_get_verify_decoder_error_stats(const FLAC__FileEncoder *encoder, FLAC__uint64 *absolute_sample, unsigned *frame_number, unsigned *channel, unsigned *sample, FLAC__int32 *expected, FLAC__int32 *got)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__seekable_stream_encoder_get_verify_decoder_error_stats(encoder->private_->seekable_stream_encoder, absolute_sample, frame_number, channel, sample, expected, got);
+}
+
+FLAC_API FLAC__bool FLAC__file_encoder_get_verify(const FLAC__FileEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	return FLAC__seekable_stream_encoder_get_verify(encoder->private_->seekable_stream_encoder);
+}
+
+FLAC_API FLAC__bool FLAC__file_encoder_get_streamable_subset(const FLAC__FileEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	return FLAC__seekable_stream_encoder_get_streamable_subset(encoder->private_->seekable_stream_encoder);
+}
+
+FLAC_API FLAC__bool FLAC__file_encoder_get_do_mid_side_stereo(const FLAC__FileEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	return FLAC__seekable_stream_encoder_get_do_mid_side_stereo(encoder->private_->seekable_stream_encoder);
+}
+
+FLAC_API FLAC__bool FLAC__file_encoder_get_loose_mid_side_stereo(const FLAC__FileEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	return FLAC__seekable_stream_encoder_get_loose_mid_side_stereo(encoder->private_->seekable_stream_encoder);
+}
+
+FLAC_API unsigned FLAC__file_encoder_get_channels(const FLAC__FileEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	return FLAC__seekable_stream_encoder_get_channels(encoder->private_->seekable_stream_encoder);
+}
+
+FLAC_API unsigned FLAC__file_encoder_get_bits_per_sample(const FLAC__FileEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	return FLAC__seekable_stream_encoder_get_bits_per_sample(encoder->private_->seekable_stream_encoder);
+}
+
+FLAC_API unsigned FLAC__file_encoder_get_sample_rate(const FLAC__FileEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	return FLAC__seekable_stream_encoder_get_sample_rate(encoder->private_->seekable_stream_encoder);
+}
+
+FLAC_API unsigned FLAC__file_encoder_get_blocksize(const FLAC__FileEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	return FLAC__seekable_stream_encoder_get_blocksize(encoder->private_->seekable_stream_encoder);
+}
+
+FLAC_API unsigned FLAC__file_encoder_get_max_lpc_order(const FLAC__FileEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	return FLAC__seekable_stream_encoder_get_max_lpc_order(encoder->private_->seekable_stream_encoder);
+}
+
+FLAC_API unsigned FLAC__file_encoder_get_qlp_coeff_precision(const FLAC__FileEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	return FLAC__seekable_stream_encoder_get_qlp_coeff_precision(encoder->private_->seekable_stream_encoder);
+}
+
+FLAC_API FLAC__bool FLAC__file_encoder_get_do_qlp_coeff_prec_search(const FLAC__FileEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	return FLAC__seekable_stream_encoder_get_do_qlp_coeff_prec_search(encoder->private_->seekable_stream_encoder);
+}
+
+FLAC_API FLAC__bool FLAC__file_encoder_get_do_escape_coding(const FLAC__FileEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	return FLAC__seekable_stream_encoder_get_do_escape_coding(encoder->private_->seekable_stream_encoder);
+}
+
+FLAC_API FLAC__bool FLAC__file_encoder_get_do_exhaustive_model_search(const FLAC__FileEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	return FLAC__seekable_stream_encoder_get_do_exhaustive_model_search(encoder->private_->seekable_stream_encoder);
+}
+
+FLAC_API unsigned FLAC__file_encoder_get_min_residual_partition_order(const FLAC__FileEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	return FLAC__seekable_stream_encoder_get_min_residual_partition_order(encoder->private_->seekable_stream_encoder);
+}
+
+FLAC_API unsigned FLAC__file_encoder_get_max_residual_partition_order(const FLAC__FileEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	return FLAC__seekable_stream_encoder_get_max_residual_partition_order(encoder->private_->seekable_stream_encoder);
+}
+
+FLAC_API unsigned FLAC__file_encoder_get_rice_parameter_search_dist(const FLAC__FileEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	return FLAC__seekable_stream_encoder_get_rice_parameter_search_dist(encoder->private_->seekable_stream_encoder);
+}
+
+FLAC_API FLAC__uint64 FLAC__file_encoder_get_total_samples_estimate(const FLAC__FileEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	return FLAC__seekable_stream_encoder_get_total_samples_estimate(encoder->private_->seekable_stream_encoder);
+}
+
+FLAC_API FLAC__bool FLAC__file_encoder_process(FLAC__FileEncoder *encoder, const FLAC__int32 * const buffer[], unsigned samples)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	if(!FLAC__seekable_stream_encoder_process(encoder->private_->seekable_stream_encoder, buffer, samples)) {
+		encoder->protected_->state = FLAC__FILE_ENCODER_SEEKABLE_STREAM_ENCODER_ERROR;
+		return false;
+	}
+	else
+		return true;
+}
+
+/* 'samples' is channel-wide samples, e.g. for 1 second at 44100Hz, 'samples' = 44100 regardless of the number of channels */
+FLAC_API FLAC__bool FLAC__file_encoder_process_interleaved(FLAC__FileEncoder *encoder, const FLAC__int32 buffer[], unsigned samples)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	if(!FLAC__seekable_stream_encoder_process_interleaved(encoder->private_->seekable_stream_encoder, buffer, samples)) {
+		encoder->protected_->state = FLAC__FILE_ENCODER_SEEKABLE_STREAM_ENCODER_ERROR;
+		return false;
+	}
+	else
+		return true;
+}
+
+
+/***********************************************************************
+ *
+ * Private class methods
+ *
+ ***********************************************************************/
+
+void set_defaults_(FLAC__FileEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+
+	encoder->private_->progress_callback = 0;
+	encoder->private_->client_data = 0;
+	encoder->private_->total_frames_estimate = 0;
+	encoder->private_->filename = 0;
+}
+
+FLAC__SeekableStreamEncoderSeekStatus seek_callback_(const FLAC__SeekableStreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data)
+{
+	FLAC__FileEncoder *file_encoder = (FLAC__FileEncoder*)client_data;
+
+	(void)encoder;
+
+	FLAC__ASSERT(0 != file_encoder);
+
+	if(fseek(file_encoder->private_->file, (long)absolute_byte_offset, SEEK_SET) < 0)
+		return FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_ERROR;
+	else
+		return FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_OK;
+}
+
+FLAC__SeekableStreamEncoderTellStatus tell_callback_(const FLAC__SeekableStreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
+{
+	FLAC__FileEncoder *file_encoder = (FLAC__FileEncoder*)client_data;
+	long offset;
+
+	(void)encoder;
+
+	FLAC__ASSERT(0 != file_encoder);
+
+	offset = ftell(file_encoder->private_->file);
+
+	if(offset < 0) {
+		return FLAC__SEEKABLE_STREAM_ENCODER_TELL_STATUS_ERROR;
+	}
+	else {
+		*absolute_byte_offset = (FLAC__uint64)offset;
+		return FLAC__SEEKABLE_STREAM_ENCODER_TELL_STATUS_OK;
+	}
+}
+
+#ifdef FLAC__VALGRIND_TESTING
+static size_t local__fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
+{
+	size_t ret = fwrite(ptr, size, nmemb, stream);
+	if(!ferror(stream))
+		fflush(stream);
+	return ret;
+}
+#else
+#define local__fwrite fwrite
+#endif
+
+FLAC__StreamEncoderWriteStatus write_callback_(const FLAC__SeekableStreamEncoder *encoder, const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data)
+{
+	FLAC__FileEncoder *file_encoder = (FLAC__FileEncoder*)client_data;
+
+	(void)encoder, (void)samples, (void)current_frame;
+
+	FLAC__ASSERT(0 != file_encoder);
+
+	if(local__fwrite(buffer, sizeof(FLAC__byte), bytes, file_encoder->private_->file) == bytes) {
+		file_encoder->private_->bytes_written += bytes;
+		file_encoder->private_->samples_written += samples;
+		/* we keep a high watermark on the number of frames written because
+		 * when the encoder goes back to write metadata, 'current_frame'
+		 * will drop back to 0.
+		 */
+		file_encoder->private_->frames_written = max(file_encoder->private_->frames_written, current_frame+1);
+		if(0 != file_encoder->private_->progress_callback && samples > 0)
+			file_encoder->private_->progress_callback(file_encoder, file_encoder->private_->bytes_written, file_encoder->private_->samples_written, file_encoder->private_->frames_written, file_encoder->private_->total_frames_estimate, file_encoder->private_->client_data);
+		return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
+	}
+	else
+		return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
+}
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/fixed.c
@@ -1,0 +1,231 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <math.h>
+#include "private/fixed.h"
+#include "FLAC/assert.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) ((unsigned)((x)<0? -(x) : (x)))
+
+unsigned FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], unsigned data_len, FLAC__real residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1])
+{
+	FLAC__int32 last_error_0 = data[-1];
+	FLAC__int32 last_error_1 = data[-1] - data[-2];
+	FLAC__int32 last_error_2 = last_error_1 - (data[-2] - data[-3]);
+	FLAC__int32 last_error_3 = last_error_2 - (data[-2] - 2*data[-3] + data[-4]);
+	FLAC__int32 error, save;
+	FLAC__uint32 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  = data[i]     ; total_error_0 += local_abs(error);                      save = error;
+		error -= last_error_0; total_error_1 += local_abs(error); last_error_0 = save; save = error;
+		error -= last_error_1; total_error_2 += local_abs(error); last_error_1 = save; save = error;
+		error -= last_error_2; total_error_3 += local_abs(error); last_error_2 = save; save = error;
+		error -= last_error_3; total_error_4 += local_abs(error); last_error_3 = save;
+	}
+
+	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|) */
+	FLAC__ASSERT(data_len > 0 || total_error_0 == 0);
+	FLAC__ASSERT(data_len > 0 || total_error_1 == 0);
+	FLAC__ASSERT(data_len > 0 || total_error_2 == 0);
+	FLAC__ASSERT(data_len > 0 || total_error_3 == 0);
+	FLAC__ASSERT(data_len > 0 || total_error_4 == 0);
+	residual_bits_per_sample[0] = (FLAC__real)((total_error_0 > 0) ? log(M_LN2 * (double)total_error_0 / (double)data_len) / M_LN2 : 0.0);
+	residual_bits_per_sample[1] = (FLAC__real)((total_error_1 > 0) ? log(M_LN2 * (double)total_error_1 / (double)data_len) / M_LN2 : 0.0);
+	residual_bits_per_sample[2] = (FLAC__real)((total_error_2 > 0) ? log(M_LN2 * (double)total_error_2 / (double)data_len) / M_LN2 : 0.0);
+	residual_bits_per_sample[3] = (FLAC__real)((total_error_3 > 0) ? log(M_LN2 * (double)total_error_3 / (double)data_len) / M_LN2 : 0.0);
+	residual_bits_per_sample[4] = (FLAC__real)((total_error_4 > 0) ? log(M_LN2 * (double)total_error_4 / (double)data_len) / M_LN2 : 0.0);
+
+	return order;
+}
+
+unsigned FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], unsigned data_len, FLAC__real residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1])
+{
+	FLAC__int32 last_error_0 = data[-1];
+	FLAC__int32 last_error_1 = data[-1] - data[-2];
+	FLAC__int32 last_error_2 = last_error_1 - (data[-2] - data[-3]);
+	FLAC__int32 last_error_3 = last_error_2 - (data[-2] - 2*data[-3] + data[-4]);
+	FLAC__int32 error, save;
+	/* total_error_* are 64-bits to avoid overflow when encoding
+	 * erratic signals when the bits-per-sample and blocksize are
+	 * large.
+	 */
+	FLAC__uint64 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  = data[i]     ; total_error_0 += local_abs(error);                      save = error;
+		error -= last_error_0; total_error_1 += local_abs(error); last_error_0 = save; save = error;
+		error -= last_error_1; total_error_2 += local_abs(error); last_error_1 = save; save = error;
+		error -= last_error_2; total_error_3 += local_abs(error); last_error_2 = save; save = error;
+		error -= last_error_3; total_error_4 += local_abs(error); last_error_3 = save;
+	}
+
+	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|) */
+	FLAC__ASSERT(data_len > 0 || total_error_0 == 0);
+	FLAC__ASSERT(data_len > 0 || total_error_1 == 0);
+	FLAC__ASSERT(data_len > 0 || total_error_2 == 0);
+	FLAC__ASSERT(data_len > 0 || total_error_3 == 0);
+	FLAC__ASSERT(data_len > 0 || total_error_4 == 0);
+#if defined _MSC_VER || defined __MINGW32__
+	/* with VC++ you have to spoon feed it the casting */
+	residual_bits_per_sample[0] = (FLAC__real)((total_error_0 > 0) ? log(M_LN2 * (double)(FLAC__int64)total_error_0 / (double)data_len) / M_LN2 : 0.0);
+	residual_bits_per_sample[1] = (FLAC__real)((total_error_1 > 0) ? log(M_LN2 * (double)(FLAC__int64)total_error_1 / (double)data_len) / M_LN2 : 0.0);
+	residual_bits_per_sample[2] = (FLAC__real)((total_error_2 > 0) ? log(M_LN2 * (double)(FLAC__int64)total_error_2 / (double)data_len) / M_LN2 : 0.0);
+	residual_bits_per_sample[3] = (FLAC__real)((total_error_3 > 0) ? log(M_LN2 * (double)(FLAC__int64)total_error_3 / (double)data_len) / M_LN2 : 0.0);
+	residual_bits_per_sample[4] = (FLAC__real)((total_error_4 > 0) ? log(M_LN2 * (double)(FLAC__int64)total_error_4 / (double)data_len) / M_LN2 : 0.0);
+#else
+	residual_bits_per_sample[0] = (FLAC__real)((total_error_0 > 0) ? log(M_LN2 * (double)total_error_0 / (double)data_len) / M_LN2 : 0.0);
+	residual_bits_per_sample[1] = (FLAC__real)((total_error_1 > 0) ? log(M_LN2 * (double)total_error_1 / (double)data_len) / M_LN2 : 0.0);
+	residual_bits_per_sample[2] = (FLAC__real)((total_error_2 > 0) ? log(M_LN2 * (double)total_error_2 / (double)data_len) / M_LN2 : 0.0);
+	residual_bits_per_sample[3] = (FLAC__real)((total_error_3 > 0) ? log(M_LN2 * (double)total_error_3 / (double)data_len) / M_LN2 : 0.0);
+	residual_bits_per_sample[4] = (FLAC__real)((total_error_4 > 0) ? log(M_LN2 * (double)total_error_4 / (double)data_len) / M_LN2 : 0.0);
+#endif
+
+	return order;
+}
+
+void FLAC__fixed_compute_residual(const FLAC__int32 data[], unsigned data_len, unsigned order, FLAC__int32 residual[])
+{
+	const int idata_len = (int)data_len;
+	int i;
+
+	switch(order) {
+		case 0:
+			for(i = 0; i < idata_len; i++) {
+				residual[i] = data[i];
+			}
+			break;
+		case 1:
+			for(i = 0; i < idata_len; i++) {
+				residual[i] = data[i] - data[i-1];
+			}
+			break;
+		case 2:
+			for(i = 0; i < idata_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 < idata_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 < idata_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:
+			FLAC__ASSERT(0);
+	}
+}
+
+void FLAC__fixed_restore_signal(const FLAC__int32 residual[], unsigned data_len, unsigned order, FLAC__int32 data[])
+{
+	int i, idata_len = (int)data_len;
+
+	switch(order) {
+		case 0:
+			for(i = 0; i < idata_len; i++) {
+				data[i] = residual[i];
+			}
+			break;
+		case 1:
+			for(i = 0; i < idata_len; i++) {
+				data[i] = residual[i] + data[i-1];
+			}
+			break;
+		case 2:
+			for(i = 0; i < idata_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 < idata_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 < idata_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:
+			FLAC__ASSERT(0);
+	}
+}
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/format.c
@@ -1,0 +1,403 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h> /* for qsort() */
+#include "FLAC/assert.h"
+#include "FLAC/format.h"
+#include "private/format.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef min
+#undef min
+#endif
+#define min(a,b) ((a)<(b)?(a):(b))
+
+/* adjust for compilers that can't understand using LLU suffix for uint64_t literals */
+#ifdef _MSC_VER
+#define FLAC__U64L(x) x
+#else
+#define FLAC__U64L(x) x##LLU
+#endif
+
+/* VERSION should come from configure */
+FLAC_API const char *FLAC__VERSION_STRING = VERSION;
+
+#if defined _MSC_VER || defined __MINW32__
+/* yet one more hack because of MSVC6: */
+FLAC_API const char *FLAC__VENDOR_STRING = "reference libFLAC 1.1.1 20041001";
+#else
+FLAC_API const char *FLAC__VENDOR_STRING = "reference libFLAC " VERSION " 20041001";
+#endif
+
+FLAC_API const FLAC__byte FLAC__STREAM_SYNC_STRING[4] = { 'f','L','a','C' };
+FLAC_API const unsigned FLAC__STREAM_SYNC = 0x664C6143;
+FLAC_API const unsigned FLAC__STREAM_SYNC_LEN = 32; /* bits */;
+
+FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN = 16; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN = 16; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN = 24; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN = 24; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN = 20; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN = 3; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN = 5; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN = 36; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MD5SUM_LEN = 128; /* bits */
+
+FLAC_API const unsigned FLAC__STREAM_METADATA_APPLICATION_ID_LEN = 32; /* bits */
+
+FLAC_API const unsigned FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN = 64; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN = 64; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN = 16; /* bits */
+
+FLAC_API const FLAC__uint64 FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER = FLAC__U64L(0xffffffffffffffff);
+
+FLAC_API const unsigned FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN = 32; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN = 32; /* bits */
+
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN = 64; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN = 8; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN = 3*8; /* bits */
+
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN = 64; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN = 8; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN = 12*8; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN = 1; /* bit */
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN = 1; /* bit */
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN = 6+13*8; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN = 8; /* bits */
+
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN = 128*8; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN = 64; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN = 1; /* bit */
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN = 7+258*8; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN = 8; /* bits */
+
+FLAC_API const unsigned FLAC__STREAM_METADATA_IS_LAST_LEN = 1; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_TYPE_LEN = 7; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_LENGTH_LEN = 24; /* bits */
+
+FLAC_API const unsigned FLAC__FRAME_HEADER_SYNC = 0x3ffe;
+FLAC_API const unsigned FLAC__FRAME_HEADER_SYNC_LEN = 14; /* bits */
+FLAC_API const unsigned FLAC__FRAME_HEADER_RESERVED_LEN = 2; /* bits */
+FLAC_API const unsigned FLAC__FRAME_HEADER_BLOCK_SIZE_LEN = 4; /* bits */
+FLAC_API const unsigned FLAC__FRAME_HEADER_SAMPLE_RATE_LEN = 4; /* bits */
+FLAC_API const unsigned FLAC__FRAME_HEADER_CHANNEL_ASSIGNMENT_LEN = 4; /* bits */
+FLAC_API const unsigned FLAC__FRAME_HEADER_BITS_PER_SAMPLE_LEN = 3; /* bits */
+FLAC_API const unsigned FLAC__FRAME_HEADER_ZERO_PAD_LEN = 1; /* bits */
+FLAC_API const unsigned FLAC__FRAME_HEADER_CRC_LEN = 8; /* bits */
+
+FLAC_API const unsigned FLAC__FRAME_FOOTER_CRC_LEN = 16; /* bits */
+
+FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_TYPE_LEN = 2; /* bits */
+FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN = 4; /* bits */
+FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN = 4; /* bits */
+FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN = 5; /* bits */
+
+FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER = 15; /* == (1<<FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN)-1 */
+
+FLAC_API const char * const FLAC__EntropyCodingMethodTypeString[] = {
+	"PARTITIONED_RICE"
+};
+
+FLAC_API const unsigned FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN = 4; /* bits */
+FLAC_API const unsigned FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN = 5; /* bits */
+
+FLAC_API const unsigned FLAC__SUBFRAME_ZERO_PAD_LEN = 1; /* bits */
+FLAC_API const unsigned FLAC__SUBFRAME_TYPE_LEN = 6; /* bits */
+FLAC_API const unsigned FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN = 1; /* bits */
+
+FLAC_API const unsigned FLAC__SUBFRAME_TYPE_CONSTANT_BYTE_ALIGNED_MASK = 0x00;
+FLAC_API const unsigned FLAC__SUBFRAME_TYPE_VERBATIM_BYTE_ALIGNED_MASK = 0x02;
+FLAC_API const unsigned FLAC__SUBFRAME_TYPE_FIXED_BYTE_ALIGNED_MASK = 0x10;
+FLAC_API const unsigned FLAC__SUBFRAME_TYPE_LPC_BYTE_ALIGNED_MASK = 0x40;
+
+FLAC_API const char * const FLAC__SubframeTypeString[] = {
+	"CONSTANT",
+	"VERBATIM",
+	"FIXED",
+	"LPC"
+};
+
+FLAC_API const char * const FLAC__ChannelAssignmentString[] = {
+	"INDEPENDENT",
+	"LEFT_SIDE",
+	"RIGHT_SIDE",
+	"MID_SIDE"
+};
+
+FLAC_API const char * const FLAC__FrameNumberTypeString[] = {
+	"FRAME_NUMBER_TYPE_FRAME_NUMBER",
+	"FRAME_NUMBER_TYPE_SAMPLE_NUMBER"
+};
+
+FLAC_API const char * const FLAC__MetadataTypeString[] = {
+	"STREAMINFO",
+	"PADDING",
+	"APPLICATION",
+	"SEEKTABLE",
+	"VORBIS_COMMENT",
+	"CUESHEET"
+};
+
+FLAC_API FLAC__bool FLAC__format_sample_rate_is_valid(unsigned sample_rate)
+{
+	if(
+		sample_rate == 0 ||
+		sample_rate > FLAC__MAX_SAMPLE_RATE ||
+		(
+			sample_rate >= (1u << 16) &&
+			!(sample_rate % 1000 == 0 || sample_rate % 10 == 0)
+		)
+	) {
+		return false;
+	}
+	else
+		return true;
+}
+
+FLAC_API FLAC__bool FLAC__format_seektable_is_legal(const FLAC__StreamMetadata_SeekTable *seek_table)
+{
+	unsigned i;
+	FLAC__uint64 prev_sample_number = 0;
+	FLAC__bool got_prev = false;
+
+	FLAC__ASSERT(0 != seek_table);
+
+	for(i = 0; i < seek_table->num_points; i++) {
+		if(got_prev) {
+			if(
+				seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER &&
+				seek_table->points[i].sample_number <= prev_sample_number
+			)
+				return false;
+		}
+		prev_sample_number = seek_table->points[i].sample_number;
+		got_prev = true;
+	}
+
+	return true;
+}
+
+/* used as the sort predicate for qsort() */
+static int seekpoint_compare_(const FLAC__StreamMetadata_SeekPoint *l, const FLAC__StreamMetadata_SeekPoint *r)
+{
+	/* we don't just 'return l->sample_number - r->sample_number' since the result (FLAC__int64) might overflow an 'int' */
+	if(l->sample_number == r->sample_number)
+		return 0;
+	else if(l->sample_number < r->sample_number)
+		return -1;
+	else
+		return 1;
+}
+
+FLAC_API unsigned FLAC__format_seektable_sort(FLAC__StreamMetadata_SeekTable *seek_table)
+{
+	unsigned i, j;
+	FLAC__bool first;
+
+	FLAC__ASSERT(0 != seek_table);
+
+	/* sort the seekpoints */
+	qsort(seek_table->points, seek_table->num_points, sizeof(FLAC__StreamMetadata_SeekPoint), (int (*)(const void *, const void *))seekpoint_compare_);
+
+	/* uniquify the seekpoints */
+	first = true;
+	for(i = j = 0; i < seek_table->num_points; i++) {
+		if(seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER) {
+			if(!first) {
+				if(seek_table->points[i].sample_number == seek_table->points[j-1].sample_number)
+					continue;
+			}
+		}
+		first = false;
+		seek_table->points[j++] = seek_table->points[i];
+	}
+
+	for(i = j; i < seek_table->num_points; i++) {
+		seek_table->points[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
+		seek_table->points[i].stream_offset = 0;
+		seek_table->points[i].frame_samples = 0;
+	}
+
+	return j;
+}
+
+FLAC_API FLAC__bool FLAC__format_cuesheet_is_legal(const FLAC__StreamMetadata_CueSheet *cue_sheet, FLAC__bool check_cd_da_subset, const char **violation)
+{
+	unsigned i, j;
+
+	if(check_cd_da_subset) {
+		if(cue_sheet->lead_in < 2 * 44100) {
+			if(violation) *violation = "CD-DA cue sheet must have a lead-in length of at least 2 seconds";
+			return false;
+		}
+		if(cue_sheet->lead_in % 588 != 0) {
+			if(violation) *violation = "CD-DA cue sheet lead-in length must be evenly divisible by 588 samples";
+			return false;
+		}
+	}
+
+	if(cue_sheet->num_tracks == 0) {
+		if(violation) *violation = "cue sheet must have at least one track (the lead-out)";
+		return false;
+	}
+
+	if(check_cd_da_subset && cue_sheet->tracks[cue_sheet->num_tracks-1].number != 170) {
+		if(violation) *violation = "CD-DA cue sheet must have a lead-out track number 170 (0xAA)";
+		return false;
+	}
+
+	for(i = 0; i < cue_sheet->num_tracks; i++) {
+		if(cue_sheet->tracks[i].number == 0) {
+			if(violation) *violation = "cue sheet may not have a track number 0";
+			return false;
+		}
+
+		if(check_cd_da_subset) {
+			if(!((cue_sheet->tracks[i].number >= 1 && cue_sheet->tracks[i].number <= 99) || cue_sheet->tracks[i].number == 170)) {
+				if(violation) *violation = "CD-DA cue sheet track number must be 1-99 or 170";
+				return false;
+			}
+		}
+
+		if(check_cd_da_subset && cue_sheet->tracks[i].offset % 588 != 0) {
+			if(violation) *violation = "CD-DA cue sheet track offset must be evenly divisible by 588 samples";
+			return false;
+		}
+
+		if(i < cue_sheet->num_tracks - 1) {
+			if(cue_sheet->tracks[i].num_indices == 0) {
+				if(violation) *violation = "cue sheet track must have at least one index point";
+				return false;
+			}
+
+			if(cue_sheet->tracks[i].indices[0].number > 1) {
+				if(violation) *violation = "cue sheet track's first index number must be 0 or 1";
+				return false;
+			}
+		}
+
+		for(j = 0; j < cue_sheet->tracks[i].num_indices; j++) {
+			if(check_cd_da_subset && cue_sheet->tracks[i].indices[j].offset % 588 != 0) {
+				if(violation) *violation = "CD-DA cue sheet track index offset must be evenly divisible by 588 samples";
+				return false;
+			}
+
+			if(j > 0) {
+				if(cue_sheet->tracks[i].indices[j].number != cue_sheet->tracks[i].indices[j-1].number + 1) {
+					if(violation) *violation = "cue sheet track index numbers must increase by 1";
+					return false;
+				}
+			}
+		}
+	}
+
+	return true;
+}
+
+/*
+ * These routines are private to libFLAC
+ */
+unsigned FLAC__format_get_max_rice_partition_order(unsigned blocksize, unsigned predictor_order)
+{
+	return
+		FLAC__format_get_max_rice_partition_order_from_blocksize_limited_max_and_predictor_order(
+			FLAC__format_get_max_rice_partition_order_from_blocksize(blocksize),
+			blocksize,
+			predictor_order
+		);
+}
+
+unsigned FLAC__format_get_max_rice_partition_order_from_blocksize(unsigned blocksize)
+{
+	unsigned max_rice_partition_order = 0;
+	while(!(blocksize & 1)) {
+		max_rice_partition_order++;
+		blocksize >>= 1;
+	}
+	return min(FLAC__MAX_RICE_PARTITION_ORDER, max_rice_partition_order);
+}
+
+unsigned FLAC__format_get_max_rice_partition_order_from_blocksize_limited_max_and_predictor_order(unsigned limit, unsigned blocksize, unsigned predictor_order)
+{
+	unsigned max_rice_partition_order = limit;
+
+	while(max_rice_partition_order > 0 && (blocksize >> max_rice_partition_order) <= predictor_order)
+		max_rice_partition_order--;
+
+	FLAC__ASSERT(
+		(max_rice_partition_order == 0 && blocksize >= predictor_order) ||
+		(max_rice_partition_order > 0 && blocksize >> max_rice_partition_order > predictor_order)
+	);
+
+	return max_rice_partition_order;
+}
+
+void FLAC__format_entropy_coding_method_partitioned_rice_contents_init(FLAC__EntropyCodingMethod_PartitionedRiceContents *object)
+{
+	FLAC__ASSERT(0 != object);
+
+	object->parameters = 0;
+	object->raw_bits = 0;
+	object->capacity_by_order = 0;
+}
+
+void FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(FLAC__EntropyCodingMethod_PartitionedRiceContents *object)
+{
+	FLAC__ASSERT(0 != object);
+
+	if(0 != object->parameters)
+		free(object->parameters);
+	if(0 != object->raw_bits)
+		free(object->raw_bits);
+	FLAC__format_entropy_coding_method_partitioned_rice_contents_init(object);
+}
+
+FLAC__bool FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(FLAC__EntropyCodingMethod_PartitionedRiceContents *object, unsigned max_partition_order)
+{
+	FLAC__ASSERT(0 != object);
+
+	FLAC__ASSERT(object->capacity_by_order > 0 || (0 == object->parameters && 0 == object->raw_bits));
+
+	if(object->capacity_by_order < max_partition_order) {
+		if(0 == (object->parameters = (unsigned*)realloc(object->parameters, sizeof(unsigned)*(1 << max_partition_order))))
+			return false;
+		if(0 == (object->raw_bits = (unsigned*)realloc(object->raw_bits, sizeof(unsigned)*(1 << max_partition_order))))
+			return false;
+		object->capacity_by_order = max_partition_order;
+	}
+
+	return true;
+}
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/lpc.c
@@ -1,0 +1,423 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <math.h>
+#include "FLAC/assert.h"
+#include "FLAC/format.h"
+#include "private/bitmath.h"
+#include "private/lpc.h"
+#if defined DEBUG || defined FLAC__OVERFLOW_DETECT || defined FLAC__OVERFLOW_DETECT_VERBOSE
+#include <stdio.h>
+#endif
+
+#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 FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[])
+{
+	/* a readable, but slower, version */
+#if 0
+	FLAC__real d;
+	unsigned i;
+
+	FLAC__ASSERT(lag > 0);
+	FLAC__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;
+	}
+#endif
+
+	/*
+	 * this version tends to run faster because of better data locality
+	 * ('data_len' is usually much larger than 'lag')
+	 */
+	FLAC__real d;
+	unsigned sample, coeff;
+	const unsigned limit = data_len - lag;
+
+	FLAC__ASSERT(lag > 0);
+	FLAC__ASSERT(lag <= data_len);
+
+	for(coeff = 0; coeff < lag; coeff++)
+		autoc[coeff] = 0.0;
+	for(sample = 0; sample <= limit; sample++) {
+		d = data[sample];
+		for(coeff = 0; coeff < lag; coeff++)
+			autoc[coeff] += d * data[sample+coeff];
+	}
+	for(; sample < data_len; sample++) {
+		d = data[sample];
+		for(coeff = 0; coeff < data_len - sample; coeff++)
+			autoc[coeff] += d * data[sample+coeff];
+	}
+}
+
+void FLAC__lpc_compute_lp_coefficients(const FLAC__real autoc[], unsigned max_order, FLAC__real lp_coeff[][FLAC__MAX_LPC_ORDER], FLAC__real error[])
+{
+	unsigned i, j;
+	double r, err, ref[FLAC__MAX_LPC_ORDER], lpc[FLAC__MAX_LPC_ORDER];
+
+	FLAC__ASSERT(0 < max_order);
+	FLAC__ASSERT(max_order <= FLAC__MAX_LPC_ORDER);
+	FLAC__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++) {
+			double 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] = (FLAC__real)(-lpc[j]); /* negate FIR filter coeff to get predictor coeff */
+		error[i] = (FLAC__real)err;
+	}
+}
+
+int FLAC__lpc_quantize_coefficients(const FLAC__real lp_coeff[], unsigned order, unsigned precision, FLAC__int32 qlp_coeff[], int *shift)
+{
+	unsigned i;
+	double d, cmax = -1e32;
+	FLAC__int32 qmax, qmin;
+	const int max_shiftlimit = (1 << (FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN-1)) - 1;
+	const int min_shiftlimit = -max_shiftlimit - 1;
+
+	FLAC__ASSERT(precision > 0);
+	FLAC__ASSERT(precision >= FLAC__MIN_QLP_COEFF_PRECISION);
+
+	/* drop one bit for the sign; from here on out we consider only |lp_coeff[i]| */
+	precision--;
+	qmax = 1 << precision;
+	qmin = -qmax;
+	qmax--;
+
+	for(i = 0; i < order; i++) {
+		if(lp_coeff[i] == 0.0)
+			continue;
+		d = fabs(lp_coeff[i]);
+		if(d > cmax)
+			cmax = d;
+	}
+redo_it:
+	if(cmax <= 0.0) {
+		/* => coefficients are all 0, which means our constant-detect didn't work */
+		return 2;
+	}
+	else {
+		int log2cmax;
+
+		(void)frexp(cmax, &log2cmax);
+		log2cmax--;
+		*shift = (int)precision - log2cmax - 1;
+
+		if(*shift < min_shiftlimit || *shift > max_shiftlimit) {
+#if 0
+			/*@@@ this does not seem to help at all, but was not extensively tested either: */
+			if(*shift > max_shiftlimit)
+				*shift = max_shiftlimit;
+			else
+#endif
+				return 1;
+		}
+	}
+
+	if(*shift >= 0) {
+		for(i = 0; i < order; i++) {
+			qlp_coeff[i] = (FLAC__int32)floor((double)lp_coeff[i] * (double)(1 << *shift));
+
+			/* double-check the result */
+			if(qlp_coeff[i] > qmax || qlp_coeff[i] < qmin) {
+#ifdef FLAC__OVERFLOW_DETECT
+				fprintf(stderr,"FLAC__lpc_quantize_coefficients: compensating for overflow, qlp_coeff[%u]=%d, lp_coeff[%u]=%f, cmax=%f, precision=%u, shift=%d, q=%f, f(q)=%f\n", i, qlp_coeff[i], i, lp_coeff[i], cmax, precision, *shift, (double)lp_coeff[i] * (double)(1 << *shift), floor((double)lp_coeff[i] * (double)(1 << *shift)));
+#endif
+				cmax *= 2.0;
+				goto redo_it;
+			}
+		}
+	}
+	else { /* (*shift < 0) */
+		const int nshift = -(*shift);
+#ifdef DEBUG
+		fprintf(stderr,"FLAC__lpc_quantize_coefficients: negative shift = %d\n", *shift);
+#endif
+		for(i = 0; i < order; i++) {
+			qlp_coeff[i] = (FLAC__int32)floor((double)lp_coeff[i] / (double)(1 << nshift));
+
+			/* double-check the result */
+			if(qlp_coeff[i] > qmax || qlp_coeff[i] < qmin) {
+#ifdef FLAC__OVERFLOW_DETECT
+				fprintf(stderr,"FLAC__lpc_quantize_coefficients: compensating for overflow, qlp_coeff[%u]=%d, lp_coeff[%u]=%f, cmax=%f, precision=%u, shift=%d, q=%f, f(q)=%f\n", i, qlp_coeff[i], i, lp_coeff[i], cmax, precision, *shift, (double)lp_coeff[i] / (double)(1 << nshift), floor((double)lp_coeff[i] / (double)(1 << nshift)));
+#endif
+				cmax *= 2.0;
+				goto redo_it;
+			}
+		}
+	}
+
+	return 0;
+}
+
+void FLAC__lpc_compute_residual_from_qlp_coefficients(const FLAC__int32 data[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[])
+{
+#ifdef FLAC__OVERFLOW_DETECT
+	FLAC__int64 sumo;
+#endif
+	unsigned i, j;
+	FLAC__int32 sum;
+	const FLAC__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
+	FLAC__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 += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*history);
+#if defined _MSC_VER
+			if(sumo > 2147483647I64 || sumo < -2147483648I64)
+				fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients: OVERFLOW, i=%u, j=%u, c=%d, d=%d, sumo=%I64d\n",i,j,qlp_coeff[j],*history,sumo);
+#else
+			if(sumo > 2147483647ll || sumo < -2147483648ll)
+				fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients: OVERFLOW, i=%u, j=%u, c=%d, d=%d, sumo=%lld\n",i,j,qlp_coeff[j],*history,sumo);
+#endif
+#endif
+		}
+		*(residual++) = *(data++) - (sum >> lp_quantization);
+	}
+
+	/* Here's a slower but clearer version:
+	for(i = 0; i < data_len; i++) {
+		sum = 0;
+		for(j = 0; j < order; j++)
+			sum += qlp_coeff[j] * data[i-j-1];
+		residual[i] = data[i] - (sum >> lp_quantization);
+	}
+	*/
+}
+
+void FLAC__lpc_compute_residual_from_qlp_coefficients_wide(const FLAC__int32 data[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[])
+{
+	unsigned i, j;
+	FLAC__int64 sum;
+	const FLAC__int32 *history;
+
+#ifdef FLAC__OVERFLOW_DETECT_VERBOSE
+	fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients_wide: 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
+	FLAC__ASSERT(order > 0);
+
+	for(i = 0; i < data_len; i++) {
+		sum = 0;
+		history = data;
+		for(j = 0; j < order; j++)
+			sum += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*(--history));
+#ifdef FLAC__OVERFLOW_DETECT
+		if(FLAC__bitmath_silog2_wide(sum >> lp_quantization) > 32) {
+			fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients_wide: OVERFLOW, i=%u, sum=%lld\n", i, sum >> lp_quantization);
+			break;
+		}
+		if(FLAC__bitmath_silog2_wide((FLAC__int64)(*data) - (sum >> lp_quantization)) > 32) {
+			fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients_wide: OVERFLOW, i=%u, data=%d, sum=%lld, residual=%lld\n", i, *data, sum >> lp_quantization, (FLAC__int64)(*data) - (sum >> lp_quantization));
+			break;
+		}
+#endif
+		*(residual++) = *(data++) - (FLAC__int32)(sum >> lp_quantization);
+	}
+}
+
+void FLAC__lpc_restore_signal(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[])
+{
+#ifdef FLAC__OVERFLOW_DETECT
+	FLAC__int64 sumo;
+#endif
+	unsigned i, j;
+	FLAC__int32 sum;
+	const FLAC__int32 *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
+	FLAC__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 += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*history);
+#if defined _MSC_VER
+			if(sumo > 2147483647I64 || sumo < -2147483648I64)
+				fprintf(stderr,"FLAC__lpc_restore_signal: OVERFLOW, i=%u, j=%u, c=%d, d=%d, sumo=%I64d\n",i,j,qlp_coeff[j],*history,sumo);
+#else
+			if(sumo > 2147483647ll || sumo < -2147483648ll)
+				fprintf(stderr,"FLAC__lpc_restore_signal: OVERFLOW, i=%u, j=%u, c=%d, d=%d, sumo=%lld\n",i,j,qlp_coeff[j],*history,sumo);
+#endif
+#endif
+		}
+		*(data++) = *(residual++) + (sum >> lp_quantization);
+	}
+
+	/* Here's a slower but clearer version:
+	for(i = 0; i < data_len; i++) {
+		sum = 0;
+		for(j = 0; j < order; j++)
+			sum += qlp_coeff[j] * data[i-j-1];
+		data[i] = residual[i] + (sum >> lp_quantization);
+	}
+	*/
+}
+
+void FLAC__lpc_restore_signal_wide(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[])
+{
+	unsigned i, j;
+	FLAC__int64 sum;
+	const FLAC__int32 *history;
+
+#ifdef FLAC__OVERFLOW_DETECT_VERBOSE
+	fprintf(stderr,"FLAC__lpc_restore_signal_wide: 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
+	FLAC__ASSERT(order > 0);
+
+	for(i = 0; i < data_len; i++) {
+		sum = 0;
+		history = data;
+		for(j = 0; j < order; j++)
+			sum += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*(--history));
+#ifdef FLAC__OVERFLOW_DETECT
+		if(FLAC__bitmath_silog2_wide(sum >> lp_quantization) > 32) {
+			fprintf(stderr,"FLAC__lpc_restore_signal_wide: OVERFLOW, i=%u, sum=%lld\n", i, sum >> lp_quantization);
+			break;
+		}
+		if(FLAC__bitmath_silog2_wide((FLAC__int64)(*residual) + (sum >> lp_quantization)) > 32) {
+			fprintf(stderr,"FLAC__lpc_restore_signal_wide: OVERFLOW, i=%u, residual=%d, sum=%lld, data=%lld\n", i, *residual, sum >> lp_quantization, (FLAC__int64)(*residual) + (sum >> lp_quantization));
+			break;
+		}
+#endif
+		*(data++) = *(residual++) + (FLAC__int32)(sum >> lp_quantization);
+	}
+}
+
+FLAC__real FLAC__lpc_compute_expected_bits_per_residual_sample(FLAC__real lpc_error, unsigned total_samples)
+{
+	double error_scale;
+
+	FLAC__ASSERT(total_samples > 0);
+
+	error_scale = 0.5 * M_LN2 * M_LN2 / (FLAC__real)total_samples;
+
+	return FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(lpc_error, error_scale);
+}
+
+FLAC__real FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(FLAC__real lpc_error, double error_scale)
+{
+	if(lpc_error > 0.0) {
+		FLAC__real bps = (FLAC__real)((double)0.5 * log(error_scale * lpc_error) / M_LN2);
+		if(bps >= 0.0)
+			return bps;
+		else
+			return 0.0;
+	}
+	else if(lpc_error < 0.0) { /* error should not be negative but can happen due to inadequate float resolution */
+		return (FLAC__real)1e32;
+	}
+	else {
+		return 0.0;
+	}
+}
+
+unsigned FLAC__lpc_compute_best_order(const FLAC__real lpc_error[], unsigned max_order, unsigned total_samples, unsigned bits_per_signal_sample)
+{
+	unsigned order, best_order;
+	FLAC__real best_bits, tmp_bits;
+	double error_scale;
+
+	FLAC__ASSERT(max_order > 0);
+	FLAC__ASSERT(total_samples > 0);
+
+	error_scale = 0.5 * M_LN2 * M_LN2 / (FLAC__real)total_samples;
+
+	best_order = 0;
+	best_bits = FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(lpc_error[0], error_scale) * (FLAC__real)total_samples;
+
+	for(order = 1; order < max_order; order++) {
+		tmp_bits = FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(lpc_error[order], error_scale) * (FLAC__real)(total_samples - order) + (FLAC__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 */
+}
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/md5.c
@@ -1,0 +1,315 @@
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest.  This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ *
+ * Changed so as no longer to depend on Colin Plumb's `usual.h' header
+ * definitions; now uses stuff from dpkg's config.h.
+ *  - Ian Jackson <[email protected]>.
+ * Still in the public domain.
+ *
+ * Josh Coalson: made some changes to integrate with libFLAC.
+ * Still in the public domain.
+ */
+
+#include <stdlib.h>		/* for malloc() */
+#include <string.h>		/* for memcpy() */
+
+#include "private/md5.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifndef FLaC__INLINE
+#define FLaC__INLINE
+#endif
+
+static FLAC__bool is_big_endian_host_;
+
+#ifndef ASM_MD5
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f,w,x,y,z,in,s) \
+	 (w += f(x,y,z) + in, w = (w<<s | w>>(32-s)) + x)
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data.  MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+FLaC__INLINE
+void
+FLAC__MD5Transform(FLAC__uint32 buf[4], FLAC__uint32 const in[16])
+{
+	register FLAC__uint32 a, b, c, d;
+
+	a = buf[0];
+	b = buf[1];
+	c = buf[2];
+	d = buf[3];
+
+	MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+	MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+	MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+	MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+	MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+	MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+	MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+	MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+	MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+	MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+	MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+	MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+	MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+	MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+	MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+	MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+	MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+	MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+	MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+	MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+	MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+	MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+	MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+	MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+	MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+	MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+	MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+	MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+	MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+	MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+	MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+	MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+	MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+	MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+	MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+	MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+	MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+	MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+	MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+	MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+	MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+	MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+	MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+	MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+	MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+	MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+	MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+	MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+	MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+	MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+	MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+	MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+	MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+	MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+	MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+	MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+	MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+	MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+	MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+	MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+	MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+	MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+	MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+	MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+	buf[0] += a;
+	buf[1] += b;
+	buf[2] += c;
+	buf[3] += d;
+}
+
+#endif
+
+FLaC__INLINE
+void
+byteSwap(FLAC__uint32 *buf, unsigned words)
+{
+	md5byte *p = (md5byte *)buf;
+
+	if(!is_big_endian_host_)
+		return;
+	do {
+		*buf++ = (FLAC__uint32)((unsigned)p[3] << 8 | p[2]) << 16 | ((unsigned)p[1] << 8 | p[0]);
+		p += 4;
+	} while (--words);
+}
+
+/*
+ * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void
+FLAC__MD5Init(struct FLAC__MD5Context *ctx)
+{
+	FLAC__uint32 test = 1;
+
+	is_big_endian_host_ = (*((FLAC__byte*)(&test)))? false : true;
+
+	ctx->buf[0] = 0x67452301;
+	ctx->buf[1] = 0xefcdab89;
+	ctx->buf[2] = 0x98badcfe;
+	ctx->buf[3] = 0x10325476;
+
+	ctx->bytes[0] = 0;
+	ctx->bytes[1] = 0;
+
+	ctx->internal_buf = 0;
+	ctx->capacity = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void
+FLAC__MD5Update(struct FLAC__MD5Context *ctx, md5byte const *buf, unsigned len)
+{
+	FLAC__uint32 t;
+
+	/* Update byte count */
+
+	t = ctx->bytes[0];
+	if ((ctx->bytes[0] = t + len) < t)
+		ctx->bytes[1]++;	/* Carry from low to high */
+
+	t = 64 - (t & 0x3f);	/* Space available in ctx->in (at least 1) */
+	if (t > len) {
+		memcpy((md5byte *)ctx->in + 64 - t, buf, len);
+		return;
+	}
+	/* First chunk is an odd size */
+	memcpy((md5byte *)ctx->in + 64 - t, buf, t);
+	byteSwap(ctx->in, 16);
+	FLAC__MD5Transform(ctx->buf, ctx->in);
+	buf += t;
+	len -= t;
+
+	/* Process data in 64-byte chunks */
+	while (len >= 64) {
+		memcpy(ctx->in, buf, 64);
+		byteSwap(ctx->in, 16);
+		FLAC__MD5Transform(ctx->buf, ctx->in);
+		buf += 64;
+		len -= 64;
+	}
+
+	/* Handle any remaining bytes of data. */
+	memcpy(ctx->in, buf, len);
+}
+
+/*
+ * Convert the incoming audio signal to a byte stream and FLAC__MD5Update it.
+ */
+FLAC__bool
+FLAC__MD5Accumulate(struct FLAC__MD5Context *ctx, const FLAC__int32 * const signal[], unsigned channels, unsigned samples, unsigned bytes_per_sample)
+{
+	unsigned channel, sample, a_byte;
+	FLAC__int32 a_word;
+	FLAC__byte *buf_;
+	const unsigned bytes_needed = channels * samples * bytes_per_sample;
+
+	if(ctx->capacity < bytes_needed) {
+		FLAC__byte *tmp = (FLAC__byte*)realloc(ctx->internal_buf, bytes_needed);
+		if(0 == tmp) {
+			free(ctx->internal_buf);
+			if(0 == (ctx->internal_buf = (FLAC__byte*)malloc(bytes_needed)))
+				return false;
+		}
+		ctx->internal_buf = tmp;
+		ctx->capacity = bytes_needed;
+	}
+
+	buf_ = ctx->internal_buf;
+
+#ifdef FLAC__CPU_IA32
+	if(channels == 2 && bytes_per_sample == 2) {
+		memcpy(buf_, signal[0], sizeof(FLAC__int32) * samples);
+		buf_ += sizeof(FLAC__int16);
+		for(sample = 0; sample < samples; sample++)
+			((FLAC__int16 *)buf_)[2 * sample] = (FLAC__int16)signal[1][sample];
+	}
+	else if(channels == 1 && bytes_per_sample == 2) {
+		for(sample = 0; sample < samples; sample++)
+			((FLAC__int16 *)buf_)[sample] = (FLAC__int16)signal[0][sample];
+	}
+	else
+#endif
+	for(sample = 0; sample < samples; sample++) {
+		for(channel = 0; channel < channels; channel++) {
+			a_word = signal[channel][sample];
+			for(a_byte = 0; a_byte < bytes_per_sample; a_byte++) {
+				*buf_++ = (FLAC__byte)(a_word & 0xff);
+				a_word >>= 8;
+			}
+		}
+	}
+
+	FLAC__MD5Update(ctx, ctx->internal_buf, bytes_needed);
+
+	return true;
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void
+FLAC__MD5Final(md5byte digest[16], struct FLAC__MD5Context *ctx)
+{
+	int count = ctx->bytes[0] & 0x3f;	/* Number of bytes in ctx->in */
+	md5byte *p = (md5byte *)ctx->in + count;
+
+	/* Set the first char of padding to 0x80.  There is always room. */
+	*p++ = 0x80;
+
+	/* Bytes of padding needed to make 56 bytes (-8..55) */
+	count = 56 - 1 - count;
+
+	if (count < 0) {	/* Padding forces an extra block */
+		memset(p, 0, count + 8);
+		byteSwap(ctx->in, 16);
+		FLAC__MD5Transform(ctx->buf, ctx->in);
+		p = (md5byte *)ctx->in;
+		count = 56;
+	}
+	memset(p, 0, count);
+	byteSwap(ctx->in, 14);
+
+	/* Append length in bits and transform */
+	ctx->in[14] = ctx->bytes[0] << 3;
+	ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29;
+	FLAC__MD5Transform(ctx->buf, ctx->in);
+
+	byteSwap(ctx->buf, 4);
+	memcpy(digest, ctx->buf, 16);
+	memset(ctx, 0, sizeof(ctx));	/* In case it's sensitive */
+	if(0 != ctx->internal_buf) {
+		free(ctx->internal_buf);
+		ctx->internal_buf = 0;
+		ctx->capacity = 0;
+	}
+}
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/memory.c
@@ -1,0 +1,164 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001,2002,2003,2004  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "private/memory.h"
+#include "FLAC/assert.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+void *FLAC__memory_alloc_aligned(size_t bytes, void **aligned_address)
+{
+	void *x;
+
+	FLAC__ASSERT(0 != aligned_address);
+
+#ifdef FLAC__ALIGN_MALLOC_DATA
+	/* align on 32-byte (256-bit) boundary */
+	x = malloc(bytes+31);
+	*aligned_address = (void*)(((unsigned)x + 31) & -32);
+#else
+	x = malloc(bytes);
+	*aligned_address = x;
+#endif
+	return x;
+}
+
+FLAC__bool FLAC__memory_alloc_aligned_int32_array(unsigned elements, FLAC__int32 **unaligned_pointer, FLAC__int32 **aligned_pointer)
+{
+	FLAC__int32 *pa, *pu; /* aligned pointer, unaligned pointer */
+
+	FLAC__ASSERT(elements > 0);
+	FLAC__ASSERT(0 != unaligned_pointer);
+	FLAC__ASSERT(0 != aligned_pointer);
+	FLAC__ASSERT(unaligned_pointer != aligned_pointer);
+
+	pu = (FLAC__int32*)FLAC__memory_alloc_aligned(sizeof(FLAC__int32) * elements, (void**)&pa);
+	if(0 == pu) {
+		return false;
+	}
+	else {
+		if(*unaligned_pointer != 0)
+			free(*unaligned_pointer);
+		*unaligned_pointer = pu;
+		*aligned_pointer = pa;
+		return true;
+	}
+}
+
+FLAC__bool FLAC__memory_alloc_aligned_uint32_array(unsigned elements, FLAC__uint32 **unaligned_pointer, FLAC__uint32 **aligned_pointer)
+{
+	FLAC__uint32 *pa, *pu; /* aligned pointer, unaligned pointer */
+
+	FLAC__ASSERT(elements > 0);
+	FLAC__ASSERT(0 != unaligned_pointer);
+	FLAC__ASSERT(0 != aligned_pointer);
+	FLAC__ASSERT(unaligned_pointer != aligned_pointer);
+
+	pu = (FLAC__uint32*)FLAC__memory_alloc_aligned(sizeof(FLAC__uint32) * elements, (void**)&pa);
+	if(0 == pu) {
+		return false;
+	}
+	else {
+		if(*unaligned_pointer != 0)
+			free(*unaligned_pointer);
+		*unaligned_pointer = pu;
+		*aligned_pointer = pa;
+		return true;
+	}
+}
+
+FLAC__bool FLAC__memory_alloc_aligned_uint64_array(unsigned elements, FLAC__uint64 **unaligned_pointer, FLAC__uint64 **aligned_pointer)
+{
+	FLAC__uint64 *pa, *pu; /* aligned pointer, unaligned pointer */
+
+	FLAC__ASSERT(elements > 0);
+	FLAC__ASSERT(0 != unaligned_pointer);
+	FLAC__ASSERT(0 != aligned_pointer);
+	FLAC__ASSERT(unaligned_pointer != aligned_pointer);
+
+	pu = (FLAC__uint64*)FLAC__memory_alloc_aligned(sizeof(FLAC__uint64) * elements, (void**)&pa);
+	if(0 == pu) {
+		return false;
+	}
+	else {
+		if(*unaligned_pointer != 0)
+			free(*unaligned_pointer);
+		*unaligned_pointer = pu;
+		*aligned_pointer = pa;
+		return true;
+	}
+}
+
+FLAC__bool FLAC__memory_alloc_aligned_unsigned_array(unsigned elements, unsigned **unaligned_pointer, unsigned **aligned_pointer)
+{
+	unsigned *pa, *pu; /* aligned pointer, unaligned pointer */
+
+	FLAC__ASSERT(elements > 0);
+	FLAC__ASSERT(0 != unaligned_pointer);
+	FLAC__ASSERT(0 != aligned_pointer);
+	FLAC__ASSERT(unaligned_pointer != aligned_pointer);
+
+	pu = (unsigned*)FLAC__memory_alloc_aligned(sizeof(unsigned) * elements, (void**)&pa);
+	if(0 == pu) {
+		return false;
+	}
+	else {
+		if(*unaligned_pointer != 0)
+			free(*unaligned_pointer);
+		*unaligned_pointer = pu;
+		*aligned_pointer = pa;
+		return true;
+	}
+}
+
+FLAC__bool FLAC__memory_alloc_aligned_real_array(unsigned elements, FLAC__real **unaligned_pointer, FLAC__real **aligned_pointer)
+{
+	FLAC__real *pa, *pu; /* aligned pointer, unaligned pointer */
+
+	FLAC__ASSERT(elements > 0);
+	FLAC__ASSERT(0 != unaligned_pointer);
+	FLAC__ASSERT(0 != aligned_pointer);
+	FLAC__ASSERT(unaligned_pointer != aligned_pointer);
+
+	pu = (FLAC__real*)FLAC__memory_alloc_aligned(sizeof(FLAC__real) * elements, (void**)&pa);
+	if(0 == pu) {
+		return false;
+	}
+	else {
+		if(*unaligned_pointer != 0)
+			free(*unaligned_pointer);
+		*unaligned_pointer = pu;
+		*aligned_pointer = pa;
+		return true;
+	}
+}
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/metadata_iterators.c
@@ -1,0 +1,2962 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001,2002,2003,2004  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined _MSC_VER || defined __MINGW32__
+#include <sys/utime.h> /* for utime() */
+#include <io.h> /* for chmod() */
+#else
+#include <sys/types.h> /* some flavors of BSD (like OS X) require this to get time_t */
+#include <utime.h> /* for utime() */
+#include <unistd.h> /* for chown(), unlink() */
+#endif
+#include <sys/stat.h> /* for stat(), maybe chmod() */
+
+#include "private/metadata.h"
+
+#include "FLAC/assert.h"
+#include "FLAC/file_decoder.h"
+
+#ifdef max
+#undef max
+#endif
+#define max(a,b) ((a)>(b)?(a):(b))
+#ifdef min
+#undef min
+#endif
+#define min(a,b) ((a)<(b)?(a):(b))
+
+
+/****************************************************************************
+ *
+ * Local function declarations
+ *
+ ***************************************************************************/
+
+static void pack_uint32_(FLAC__uint32 val, FLAC__byte *b, unsigned bytes);
+static void pack_uint32_little_endian_(FLAC__uint32 val, FLAC__byte *b, unsigned bytes);
+static void pack_uint64_(FLAC__uint64 val, FLAC__byte *b, unsigned bytes);
+static FLAC__uint32 unpack_uint32_(FLAC__byte *b, unsigned bytes);
+static FLAC__uint32 unpack_uint32_little_endian_(FLAC__byte *b, unsigned bytes);
+static FLAC__uint64 unpack_uint64_(FLAC__byte *b, unsigned bytes);
+
+static FLAC__bool read_metadata_block_header_(FLAC__Metadata_SimpleIterator *iterator);
+static FLAC__bool read_metadata_block_data_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block);
+static FLAC__bool read_metadata_block_header_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__bool *is_last, FLAC__MetadataType *type, unsigned *length);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata *block);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_streaminfo_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_StreamInfo *block);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_padding_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata_Padding *block, unsigned block_length);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_application_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Application *block, unsigned block_length);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_seektable_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_SeekTable *block, unsigned block_length);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_entry_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_VorbisComment_Entry *entry);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_VorbisComment *block);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_track_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_CueSheet_Track *track);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_CueSheet *block);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_unknown_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Unknown *block, unsigned block_length);
+
+static FLAC__bool write_metadata_block_header_(FILE *file, FLAC__Metadata_SimpleIteratorStatus *status, const FLAC__StreamMetadata *block);
+static FLAC__bool write_metadata_block_data_(FILE *file, FLAC__Metadata_SimpleIteratorStatus *status, const FLAC__StreamMetadata *block);
+static FLAC__bool write_metadata_block_header_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata *block);
+static FLAC__bool write_metadata_block_data_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata *block);
+static FLAC__bool write_metadata_block_data_streaminfo_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_StreamInfo *block);
+static FLAC__bool write_metadata_block_data_padding_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Padding *block, unsigned block_length);
+static FLAC__bool write_metadata_block_data_application_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Application *block, unsigned block_length);
+static FLAC__bool write_metadata_block_data_seektable_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_SeekTable *block);
+static FLAC__bool write_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_VorbisComment *block);
+static FLAC__bool write_metadata_block_data_cuesheet_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_CueSheet *block);
+static FLAC__bool write_metadata_block_data_unknown_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Unknown *block, unsigned block_length);
+
+static FLAC__bool write_metadata_block_stationary_(FLAC__Metadata_SimpleIterator *iterator, const FLAC__StreamMetadata *block);
+static FLAC__bool write_metadata_block_stationary_with_padding_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, unsigned padding_length, FLAC__bool padding_is_last);
+static FLAC__bool rewrite_whole_file_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool append);
+
+static void simple_iterator_push_(FLAC__Metadata_SimpleIterator *iterator);
+static FLAC__bool simple_iterator_pop_(FLAC__Metadata_SimpleIterator *iterator);
+
+static unsigned seek_to_first_metadata_block_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb);
+static unsigned seek_to_first_metadata_block_(FILE *f);
+
+static FLAC__bool simple_iterator_copy_file_prefix_(FLAC__Metadata_SimpleIterator *iterator, FILE **tempfile, char **tempfilename, FLAC__bool append);
+static FLAC__bool simple_iterator_copy_file_postfix_(FLAC__Metadata_SimpleIterator *iterator, FILE **tempfile, char **tempfilename, int fixup_is_last_code, long fixup_is_last_flag_offset, FLAC__bool backup);
+
+static FLAC__bool copy_n_bytes_from_file_(FILE *file, FILE *tempfile, unsigned bytes/*@@@ 4G limit*/, FLAC__Metadata_SimpleIteratorStatus *status);
+static FLAC__bool copy_n_bytes_from_file_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write_cb, unsigned bytes/*@@@ 4G limit*/, FLAC__Metadata_SimpleIteratorStatus *status);
+static FLAC__bool copy_remaining_bytes_from_file_(FILE *file, FILE *tempfile, FLAC__Metadata_SimpleIteratorStatus *status);
+static FLAC__bool copy_remaining_bytes_from_file_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Eof eof_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write_cb, FLAC__Metadata_SimpleIteratorStatus *status);
+
+static FLAC__bool open_tempfile_(const char *filename, const char *tempfile_path_prefix, FILE **tempfile, char **tempfilename, FLAC__Metadata_SimpleIteratorStatus *status);
+static FLAC__bool transport_tempfile_(const char *filename, FILE **tempfile, char **tempfilename, FLAC__Metadata_SimpleIteratorStatus *status);
+static void cleanup_tempfile_(FILE **tempfile, char **tempfilename);
+
+static FLAC__bool get_file_stats_(const char *filename, struct stat *stats);
+static void set_file_stats_(const char *filename, struct stat *stats);
+
+static int fseek_wrapper_(FLAC__IOHandle handle, FLAC__int64 offset, int whence);
+static FLAC__int64 ftell_wrapper_(FLAC__IOHandle handle);
+
+static FLAC__Metadata_ChainStatus get_equivalent_status_(FLAC__Metadata_SimpleIteratorStatus status);
+
+
+#ifdef FLAC__VALGRIND_TESTING
+static size_t local__fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
+{
+	size_t ret = fwrite(ptr, size, nmemb, stream);
+	if(!ferror(stream))
+		fflush(stream);
+	return ret;
+}
+#else
+#define local__fwrite fwrite
+#endif
+
+/****************************************************************************
+ *
+ * Level 0 implementation
+ *
+ ***************************************************************************/
+
+static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__FileDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const 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);
+
+typedef struct {
+	FLAC__bool got_error;
+	FLAC__bool got_object;
+	FLAC__StreamMetadata *object;
+} level0_client_data;
+
+FLAC_API FLAC__bool FLAC__metadata_get_streaminfo(const char *filename, FLAC__StreamMetadata *streaminfo)
+{
+	level0_client_data cd;
+	FLAC__FileDecoder *decoder;
+
+	FLAC__ASSERT(0 != filename);
+	FLAC__ASSERT(0 != streaminfo);
+
+	decoder = FLAC__file_decoder_new();
+
+	if(0 == decoder)
+		return false;
+
+	cd.got_error = false;
+	cd.got_object = false;
+	cd.object = 0;
+
+	FLAC__file_decoder_set_md5_checking(decoder, false);
+	FLAC__file_decoder_set_filename(decoder, filename);
+	FLAC__file_decoder_set_metadata_ignore_all(decoder);
+	FLAC__file_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_STREAMINFO);
+	FLAC__file_decoder_set_write_callback(decoder, write_callback_);
+	FLAC__file_decoder_set_metadata_callback(decoder, metadata_callback_);
+	FLAC__file_decoder_set_error_callback(decoder, error_callback_);
+	FLAC__file_decoder_set_client_data(decoder, &cd);
+
+	if(FLAC__file_decoder_init(decoder) != FLAC__FILE_DECODER_OK || cd.got_error) {
+		FLAC__file_decoder_finish(decoder);
+		FLAC__file_decoder_delete(decoder);
+		return false;
+	}
+
+	if(!FLAC__file_decoder_process_until_end_of_metadata(decoder) || cd.got_error) {
+		FLAC__file_decoder_finish(decoder);
+		FLAC__file_decoder_delete(decoder);
+		if(0 != cd.object)
+			FLAC__metadata_object_delete(cd.object);
+		return false;
+	}
+
+	FLAC__file_decoder_finish(decoder);
+	FLAC__file_decoder_delete(decoder);
+
+	if(cd.got_object) {
+		/* can just copy the contents since STREAMINFO has no internal structure */
+		*streaminfo = *(cd.object);
+	}
+
+	if(0 != cd.object)
+		FLAC__metadata_object_delete(cd.object);
+
+	return cd.got_object;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_get_tags(const char *filename, FLAC__StreamMetadata **tags)
+{
+	level0_client_data cd;
+	FLAC__FileDecoder *decoder;
+
+	FLAC__ASSERT(0 != filename);
+	FLAC__ASSERT(0 != tags);
+
+	decoder = FLAC__file_decoder_new();
+
+	if(0 == decoder)
+		return false;
+
+	*tags = 0;
+
+	cd.got_error = false;
+	cd.got_object = false;
+	cd.object = 0;
+
+	FLAC__file_decoder_set_md5_checking(decoder, false);
+	FLAC__file_decoder_set_filename(decoder, filename);
+	FLAC__file_decoder_set_metadata_ignore_all(decoder);
+	FLAC__file_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_VORBIS_COMMENT);
+	FLAC__file_decoder_set_write_callback(decoder, write_callback_);
+	FLAC__file_decoder_set_metadata_callback(decoder, metadata_callback_);
+	FLAC__file_decoder_set_error_callback(decoder, error_callback_);
+	FLAC__file_decoder_set_client_data(decoder, &cd);
+
+	if(FLAC__file_decoder_init(decoder) != FLAC__FILE_DECODER_OK || cd.got_error) {
+		FLAC__file_decoder_finish(decoder);
+		FLAC__file_decoder_delete(decoder);
+		return false;
+	}
+
+	if(!FLAC__file_decoder_process_until_end_of_metadata(decoder) || cd.got_error) {
+		FLAC__file_decoder_finish(decoder);
+		FLAC__file_decoder_delete(decoder);
+		if(0 != cd.object)
+			FLAC__metadata_object_delete(cd.object);
+		return false;
+	}
+
+	FLAC__file_decoder_finish(decoder);
+	FLAC__file_decoder_delete(decoder);
+
+	if(cd.got_object)
+		*tags = cd.object;
+
+	return cd.got_object;
+}
+
+FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__FileDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
+{
+	(void)decoder, (void)frame, (void)buffer, (void)client_data;
+
+	return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+
+void metadata_callback_(const FLAC__FileDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
+{
+	level0_client_data *cd = (level0_client_data *)client_data;
+	(void)decoder;
+
+	/*
+	 * we assume we only get here when the one metadata block we were
+	 * looking for was passed to us
+	 */
+	if(!cd->got_object) {
+		if(0 == (cd->object = FLAC__metadata_object_clone(metadata)))
+			cd->got_error = true;
+		else
+			cd->got_object = true;
+	}
+}
+
+void error_callback_(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+	level0_client_data *cd = (level0_client_data *)client_data;
+	(void)decoder;
+
+	if(status != FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC)
+		cd->got_error = true;
+}
+
+
+/****************************************************************************
+ *
+ * Level 1 implementation
+ *
+ ***************************************************************************/
+
+#define SIMPLE_ITERATOR_MAX_PUSH_DEPTH (1+4)
+/* 1 for initial offset, +4 for our own personal use */
+
+struct FLAC__Metadata_SimpleIterator {
+	FILE *file;
+	char *filename, *tempfile_path_prefix;
+	struct stat stats;
+	FLAC__bool has_stats;
+	FLAC__bool is_writable;
+	FLAC__Metadata_SimpleIteratorStatus status;
+	/*@@@ 2G limits here because of the offset type: */
+	long offset[SIMPLE_ITERATOR_MAX_PUSH_DEPTH];
+	long first_offset; /* this is the offset to the STREAMINFO block */
+	unsigned depth;
+	/* this is the metadata block header of the current block we are pointing to: */
+	FLAC__bool is_last;
+	FLAC__MetadataType type;
+	unsigned length;
+};
+
+FLAC_API const char * const FLAC__Metadata_SimpleIteratorStatusString[] = {
+	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK",
+	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT",
+	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE",
+	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE",
+	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE",
+	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA",
+	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR",
+	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR",
+	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR",
+	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_RENAME_ERROR",
+	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_UNLINK_ERROR",
+	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR",
+	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_INTERNAL_ERROR"
+};
+
+
+FLAC_API FLAC__Metadata_SimpleIterator *FLAC__metadata_simple_iterator_new()
+{
+	FLAC__Metadata_SimpleIterator *iterator = (FLAC__Metadata_SimpleIterator*)calloc(1, sizeof(FLAC__Metadata_SimpleIterator));
+
+	if(0 != iterator) {
+		iterator->file = 0;
+		iterator->filename = 0;
+		iterator->tempfile_path_prefix = 0;
+		iterator->has_stats = false;
+		iterator->is_writable = false;
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+		iterator->first_offset = iterator->offset[0] = -1;
+		iterator->depth = 0;
+	}
+
+	return iterator;
+}
+
+static void simple_iterator_free_guts_(FLAC__Metadata_SimpleIterator *iterator)
+{
+	FLAC__ASSERT(0 != iterator);
+
+	if(0 != iterator->file) {
+		fclose(iterator->file);
+		iterator->file = 0;
+		if(iterator->has_stats)
+			set_file_stats_(iterator->filename, &iterator->stats);
+	}
+	if(0 != iterator->filename) {
+		free(iterator->filename);
+		iterator->filename = 0;
+	}
+	if(0 != iterator->tempfile_path_prefix) {
+		free(iterator->tempfile_path_prefix);
+		iterator->tempfile_path_prefix = 0;
+	}
+}
+
+FLAC_API void FLAC__metadata_simple_iterator_delete(FLAC__Metadata_SimpleIterator *iterator)
+{
+	FLAC__ASSERT(0 != iterator);
+
+	simple_iterator_free_guts_(iterator);
+	free(iterator);
+}
+
+FLAC_API FLAC__Metadata_SimpleIteratorStatus FLAC__metadata_simple_iterator_status(FLAC__Metadata_SimpleIterator *iterator)
+{
+	FLAC__Metadata_SimpleIteratorStatus status;
+
+	FLAC__ASSERT(0 != iterator);
+
+	status = iterator->status;
+	iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+	return status;
+}
+
+static FLAC__bool simple_iterator_prime_input_(FLAC__Metadata_SimpleIterator *iterator, FLAC__bool read_only)
+{
+	unsigned ret;
+
+	FLAC__ASSERT(0 != iterator);
+
+	if(read_only || 0 == (iterator->file = fopen(iterator->filename, "r+b"))) {
+		iterator->is_writable = false;
+		if(read_only || errno == EACCES) {
+			if(0 == (iterator->file = fopen(iterator->filename, "rb"))) {
+				iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE;
+				return false;
+			}
+		}
+		else {
+			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE;
+			return false;
+		}
+	}
+	else {
+		iterator->is_writable = true;
+	}
+
+	ret = seek_to_first_metadata_block_(iterator->file);
+	switch(ret) {
+		case 0:
+			iterator->depth = 0;
+			iterator->first_offset = iterator->offset[iterator->depth] = ftell(iterator->file);
+			return read_metadata_block_header_(iterator);
+		case 1:
+			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+			return false;
+		case 2:
+			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+			return false;
+		case 3:
+			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE;
+			return false;
+		default:
+			FLAC__ASSERT(0);
+			return false;
+	}
+}
+
+#if 0
+@@@ If we decide to finish implementing this, put this comment back in metadata.h
+/*
+ * The 'tempfile_path_prefix' allows you to specify a directory where
+ * tempfiles should go.  Remember that if your metadata edits cause the
+ * FLAC file to grow, the entire file will have to be rewritten.  If
+ * 'tempfile_path_prefix' is NULL, the temp file will be written in the
+ * same directory as the original FLAC file.  This makes replacing the
+ * original with the tempfile fast but requires extra space in the same
+ * partition for the tempfile.  If space is a problem, you can pass a
+ * directory name belonging to a different partition in
+ * 'tempfile_path_prefix'.  Note that you should use the forward slash
+ * '/' as the directory separator.  A trailing slash is not needed; it
+ * will be added automatically.
+ */
+FLAC__bool FLAC__metadata_simple_iterator_init(FLAC__Metadata_SimpleIterator *iterator, const char *filename, FLAC__bool preserve_file_stats, const char *tempfile_path_prefix);
+#endif
+
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_init(FLAC__Metadata_SimpleIterator *iterator, const char *filename, FLAC__bool read_only, FLAC__bool preserve_file_stats)
+{
+	const char *tempfile_path_prefix = 0; /*@@@ search for comments near 'rename(...)' for what it will take to finish implementing this */
+
+	FLAC__ASSERT(0 != iterator);
+	FLAC__ASSERT(0 != filename);
+
+	simple_iterator_free_guts_(iterator);
+
+	if(!read_only && preserve_file_stats)
+		iterator->has_stats = get_file_stats_(filename, &iterator->stats);
+
+	if(0 == (iterator->filename = strdup(filename))) {
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+		return false;
+	}
+	if(0 != tempfile_path_prefix && 0 == (iterator->tempfile_path_prefix = strdup(tempfile_path_prefix))) {
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+		return false;
+	}
+
+	return simple_iterator_prime_input_(iterator, read_only);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_is_writable(const FLAC__Metadata_SimpleIterator *iterator)
+{
+	FLAC__ASSERT(0 != iterator);
+	FLAC__ASSERT(0 != iterator->file);
+
+	return iterator->is_writable;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_next(FLAC__Metadata_SimpleIterator *iterator)
+{
+	FLAC__ASSERT(0 != iterator);
+	FLAC__ASSERT(0 != iterator->file);
+
+	if(iterator->is_last)
+		return false;
+
+	if(0 != fseek(iterator->file, iterator->length, SEEK_CUR)) {
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+		return false;
+	}
+
+	iterator->offset[iterator->depth] = ftell(iterator->file);
+
+	return read_metadata_block_header_(iterator);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_prev(FLAC__Metadata_SimpleIterator *iterator)
+{
+	long this_offset;
+
+	FLAC__ASSERT(0 != iterator);
+	FLAC__ASSERT(0 != iterator->file);
+
+	if(iterator->offset[iterator->depth] == iterator->first_offset)
+		return false;
+
+	if(0 != fseek(iterator->file, iterator->first_offset, SEEK_SET)) {
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+		return false;
+	}
+	this_offset = iterator->first_offset;
+	if(!read_metadata_block_header_(iterator))
+		return false;
+
+	/* we ignore any error from ftell() and catch it in fseek() */
+	while(ftell(iterator->file) + (long)iterator->length < iterator->offset[iterator->depth]) {
+		if(0 != fseek(iterator->file, iterator->length, SEEK_CUR)) {
+			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+			return false;
+		}
+		this_offset = ftell(iterator->file);
+		if(!read_metadata_block_header_(iterator))
+			return false;
+	}
+
+	iterator->offset[iterator->depth] = this_offset;
+
+	return true;
+}
+
+FLAC_API FLAC__MetadataType FLAC__metadata_simple_iterator_get_block_type(const FLAC__Metadata_SimpleIterator *iterator)
+{
+	FLAC__ASSERT(0 != iterator);
+	FLAC__ASSERT(0 != iterator->file);
+
+	return iterator->type;
+}
+
+FLAC_API FLAC__StreamMetadata *FLAC__metadata_simple_iterator_get_block(FLAC__Metadata_SimpleIterator *iterator)
+{
+	FLAC__StreamMetadata *block = FLAC__metadata_object_new(iterator->type);
+
+	FLAC__ASSERT(0 != iterator);
+	FLAC__ASSERT(0 != iterator->file);
+
+	if(0 != block) {
+		block->is_last = iterator->is_last;
+		block->length = iterator->length;
+
+		if(!read_metadata_block_data_(iterator, block)) {
+			FLAC__metadata_object_delete(block);
+			return 0;
+		}
+
+		/* back up to the beginning of the block data to stay consistent */
+		if(0 != fseek(iterator->file, iterator->offset[iterator->depth] + FLAC__STREAM_METADATA_HEADER_LENGTH, SEEK_SET)) {
+			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+			FLAC__metadata_object_delete(block);
+			return 0;
+		}
+	}
+	else
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+	return block;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_set_block(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool use_padding)
+{
+	FLAC__ASSERT_DECLARATION(long debug_target_offset = iterator->offset[iterator->depth];)
+	FLAC__bool ret;
+
+	FLAC__ASSERT(0 != iterator);
+	FLAC__ASSERT(0 != iterator->file);
+	FLAC__ASSERT(0 != block);
+
+	if(!iterator->is_writable) {
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE;
+		return false;
+	}
+
+	if(iterator->type == FLAC__METADATA_TYPE_STREAMINFO || block->type == FLAC__METADATA_TYPE_STREAMINFO) {
+		if(iterator->type != block->type) {
+			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT;
+			return false;
+		}
+	}
+
+	block->is_last = iterator->is_last;
+
+	if(iterator->length == block->length)
+		return write_metadata_block_stationary_(iterator, block);
+	else if(iterator->length > block->length) {
+		if(use_padding && iterator->length >= FLAC__STREAM_METADATA_HEADER_LENGTH + block->length) {
+			ret = write_metadata_block_stationary_with_padding_(iterator, block, iterator->length - FLAC__STREAM_METADATA_HEADER_LENGTH - block->length, block->is_last);
+			FLAC__ASSERT(!ret || iterator->offset[iterator->depth] == debug_target_offset);
+			FLAC__ASSERT(!ret || ftell(iterator->file) == debug_target_offset + (long)FLAC__STREAM_METADATA_HEADER_LENGTH);
+			return ret;
+		}
+		else {
+			ret = rewrite_whole_file_(iterator, block, /*append=*/false);
+			FLAC__ASSERT(!ret || iterator->offset[iterator->depth] == debug_target_offset);
+			FLAC__ASSERT(!ret || ftell(iterator->file) == debug_target_offset + (long)FLAC__STREAM_METADATA_HEADER_LENGTH);
+			return ret;
+		}
+	}
+	else /* iterator->length < block->length */ {
+		unsigned padding_leftover = 0;
+		FLAC__bool padding_is_last = false;
+		if(use_padding) {
+			/* first see if we can even use padding */
+			if(iterator->is_last) {
+				use_padding = false;
+			}
+			else {
+				const unsigned extra_padding_bytes_required = block->length - iterator->length;
+				simple_iterator_push_(iterator);
+				if(!FLAC__metadata_simple_iterator_next(iterator)) {
+					(void)simple_iterator_pop_(iterator);
+					return false;
+				}
+				if(iterator->type != FLAC__METADATA_TYPE_PADDING) {
+					use_padding = false;
+				}
+				else {
+					if(FLAC__STREAM_METADATA_HEADER_LENGTH + iterator->length == extra_padding_bytes_required) {
+						padding_leftover = 0;
+						block->is_last = iterator->is_last;
+					}
+					else if(iterator->length < extra_padding_bytes_required)
+						use_padding = false;
+					else {
+						padding_leftover = FLAC__STREAM_METADATA_HEADER_LENGTH + iterator->length - extra_padding_bytes_required;
+						padding_is_last = iterator->is_last;
+						block->is_last = false;
+					}
+				}
+				if(!simple_iterator_pop_(iterator))
+					return false;
+			}
+		}
+		if(use_padding) {
+			if(padding_leftover == 0) {
+				ret = write_metadata_block_stationary_(iterator, block);
+				FLAC__ASSERT(!ret || iterator->offset[iterator->depth] == debug_target_offset);
+				FLAC__ASSERT(!ret || ftell(iterator->file) == debug_target_offset + (long)FLAC__STREAM_METADATA_HEADER_LENGTH);
+				return ret;
+			}
+			else {
+				FLAC__ASSERT(padding_leftover >= FLAC__STREAM_METADATA_HEADER_LENGTH);
+				ret = write_metadata_block_stationary_with_padding_(iterator, block, padding_leftover - FLAC__STREAM_METADATA_HEADER_LENGTH, padding_is_last);
+				FLAC__ASSERT(!ret || iterator->offset[iterator->depth] == debug_target_offset);
+				FLAC__ASSERT(!ret || ftell(iterator->file) == debug_target_offset + (long)FLAC__STREAM_METADATA_HEADER_LENGTH);
+				return ret;
+			}
+		}
+		else {
+			ret = rewrite_whole_file_(iterator, block, /*append=*/false);
+			FLAC__ASSERT(!ret || iterator->offset[iterator->depth] == debug_target_offset);
+			FLAC__ASSERT(!ret || ftell(iterator->file) == debug_target_offset + (long)FLAC__STREAM_METADATA_HEADER_LENGTH);
+			return ret;
+		}
+	}
+}
+
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_insert_block_after(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool use_padding)
+{
+	unsigned padding_leftover = 0;
+	FLAC__bool padding_is_last = false;
+
+	FLAC__ASSERT_DECLARATION(long debug_target_offset = iterator->offset[iterator->depth] + FLAC__STREAM_METADATA_HEADER_LENGTH + iterator->length;)
+	FLAC__bool ret;
+
+	FLAC__ASSERT(0 != iterator);
+	FLAC__ASSERT(0 != iterator->file);
+	FLAC__ASSERT(0 != block);
+
+	if(!iterator->is_writable)
+		return false;
+
+	if(block->type == FLAC__METADATA_TYPE_STREAMINFO) {
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT;
+		return false;
+	}
+
+	block->is_last = iterator->is_last;
+
+	if(use_padding) {
+		/* first see if we can even use padding */
+		if(iterator->is_last) {
+			use_padding = false;
+		}
+		else {
+			simple_iterator_push_(iterator);
+			if(!FLAC__metadata_simple_iterator_next(iterator)) {
+				(void)simple_iterator_pop_(iterator);
+				return false;
+			}
+			if(iterator->type != FLAC__METADATA_TYPE_PADDING) {
+				use_padding = false;
+			}
+			else {
+				if(iterator->length == block->length) {
+					padding_leftover = 0;
+					block->is_last = iterator->is_last;
+				}
+				else if(iterator->length < FLAC__STREAM_METADATA_HEADER_LENGTH + block->length)
+					use_padding = false;
+				else {
+					padding_leftover = iterator->length - block->length;
+					padding_is_last = iterator->is_last;
+					block->is_last = false;
+				}
+			}
+			if(!simple_iterator_pop_(iterator))
+				return false;
+		}
+	}
+	if(use_padding) {
+		/* move to the next block, which is suitable padding */
+		if(!FLAC__metadata_simple_iterator_next(iterator))
+			return false;
+		if(padding_leftover == 0) {
+			ret = write_metadata_block_stationary_(iterator, block);
+			FLAC__ASSERT(iterator->offset[iterator->depth] == debug_target_offset);
+			FLAC__ASSERT(ftell(iterator->file) == debug_target_offset + (long)FLAC__STREAM_METADATA_HEADER_LENGTH);
+			return ret;
+		}
+		else {
+			FLAC__ASSERT(padding_leftover >= FLAC__STREAM_METADATA_HEADER_LENGTH);
+			ret = write_metadata_block_stationary_with_padding_(iterator, block, padding_leftover - FLAC__STREAM_METADATA_HEADER_LENGTH, padding_is_last);
+			FLAC__ASSERT(iterator->offset[iterator->depth] == debug_target_offset);
+			FLAC__ASSERT(ftell(iterator->file) == debug_target_offset + (long)FLAC__STREAM_METADATA_HEADER_LENGTH);
+			return ret;
+		}
+	}
+	else {
+		ret = rewrite_whole_file_(iterator, block, /*append=*/true);
+		FLAC__ASSERT(iterator->offset[iterator->depth] == debug_target_offset);
+		FLAC__ASSERT(ftell(iterator->file) == debug_target_offset + (long)FLAC__STREAM_METADATA_HEADER_LENGTH);
+		return ret;
+	}
+}
+
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_delete_block(FLAC__Metadata_SimpleIterator *iterator, FLAC__bool use_padding)
+{
+	FLAC__ASSERT_DECLARATION(long debug_target_offset = iterator->offset[iterator->depth];)
+	FLAC__bool ret;
+
+	if(iterator->type == FLAC__METADATA_TYPE_STREAMINFO) {
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT;
+		return false;
+	}
+
+	if(use_padding) {
+		FLAC__StreamMetadata *padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING);
+		if(0 == padding) {
+			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+			return false;
+		}
+		padding->length = iterator->length;
+		if(!FLAC__metadata_simple_iterator_set_block(iterator, padding, false)) {
+			FLAC__metadata_object_delete(padding);
+			return false;
+		}
+		FLAC__metadata_object_delete(padding);
+		if(!FLAC__metadata_simple_iterator_prev(iterator))
+			return false;
+		FLAC__ASSERT(iterator->offset[iterator->depth] + (long)FLAC__STREAM_METADATA_HEADER_LENGTH + (long)iterator->length == debug_target_offset);
+		FLAC__ASSERT(ftell(iterator->file) + (long)iterator->length == debug_target_offset);
+		return true;
+	}
+	else {
+		ret = rewrite_whole_file_(iterator, 0, /*append=*/false);
+		FLAC__ASSERT(iterator->offset[iterator->depth] + (long)FLAC__STREAM_METADATA_HEADER_LENGTH + (long)iterator->length == debug_target_offset);
+		FLAC__ASSERT(ftell(iterator->file) + (long)iterator->length == debug_target_offset);
+		return ret;
+	}
+}
+
+
+
+/****************************************************************************
+ *
+ * Level 2 implementation
+ *
+ ***************************************************************************/
+
+
+typedef struct FLAC__Metadata_Node {
+	FLAC__StreamMetadata *data;
+	struct FLAC__Metadata_Node *prev, *next;
+} FLAC__Metadata_Node;
+
+struct FLAC__Metadata_Chain {
+	char *filename; /* will be NULL if using callbacks */
+	FLAC__Metadata_Node *head;
+	FLAC__Metadata_Node *tail;
+	unsigned nodes;
+	FLAC__Metadata_ChainStatus status;
+	long first_offset, last_offset; /*@@@ 2G limit */
+	/*
+	 * This is the length of the chain initially read from the FLAC file.
+	 * it is used to compare against the current length to decide whether
+	 * or not the whole file has to be rewritten.
+	 */
+	unsigned initial_length; /*@@@ 4G limit */
+};
+
+struct FLAC__Metadata_Iterator {
+	FLAC__Metadata_Chain *chain;
+	FLAC__Metadata_Node *current;
+};
+
+FLAC_API const char * const FLAC__Metadata_ChainStatusString[] = {
+	"FLAC__METADATA_CHAIN_STATUS_OK",
+	"FLAC__METADATA_CHAIN_STATUS_ILLEGAL_INPUT",
+	"FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE",
+	"FLAC__METADATA_CHAIN_STATUS_NOT_A_FLAC_FILE",
+	"FLAC__METADATA_CHAIN_STATUS_NOT_WRITABLE",
+	"FLAC__METADATA_CHAIN_STATUS_BAD_METADATA",
+	"FLAC__METADATA_CHAIN_STATUS_READ_ERROR",
+	"FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR",
+	"FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR",
+	"FLAC__METADATA_CHAIN_STATUS_RENAME_ERROR",
+	"FLAC__METADATA_CHAIN_STATUS_UNLINK_ERROR",
+	"FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR",
+	"FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR",
+	"FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS",
+	"FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH",
+	"FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL"
+};
+
+
+static FLAC__Metadata_Node *node_new_()
+{
+	return (FLAC__Metadata_Node*)calloc(1, sizeof(FLAC__Metadata_Node));
+}
+
+static void node_delete_(FLAC__Metadata_Node *node)
+{
+	FLAC__ASSERT(0 != node);
+	if(0 != node->data)
+		FLAC__metadata_object_delete(node->data);
+	free(node);
+}
+
+static void chain_init_(FLAC__Metadata_Chain *chain)
+{
+	FLAC__ASSERT(0 != chain);
+
+	chain->filename = 0;
+	chain->head = chain->tail = 0;
+	chain->nodes = 0;
+	chain->status = FLAC__METADATA_CHAIN_STATUS_OK;
+	chain->initial_length = 0;
+}
+
+static void chain_clear_(FLAC__Metadata_Chain *chain)
+{
+	FLAC__Metadata_Node *node, *next;
+
+	FLAC__ASSERT(0 != chain);
+
+	for(node = chain->head; node; ) {
+		next = node->next;
+		node_delete_(node);
+		node = next;
+	}
+
+	if(0 != chain->filename)
+		free(chain->filename);
+
+	chain_init_(chain);
+}
+
+static void chain_append_node_(FLAC__Metadata_Chain *chain, FLAC__Metadata_Node *node)
+{
+	FLAC__ASSERT(0 != chain);
+	FLAC__ASSERT(0 != node);
+	FLAC__ASSERT(0 != node->data);
+
+	node->next = node->prev = 0;
+	node->data->is_last = true;
+	if(0 != chain->tail)
+		chain->tail->data->is_last = false;
+
+	if(0 == chain->head)
+		chain->head = node;
+	else {
+		FLAC__ASSERT(0 != chain->tail);
+		chain->tail->next = node;
+		node->prev = chain->tail;
+	}
+	chain->tail = node;
+	chain->nodes++;
+}
+
+static void chain_remove_node_(FLAC__Metadata_Chain *chain, FLAC__Metadata_Node *node)
+{
+	FLAC__ASSERT(0 != chain);
+	FLAC__ASSERT(0 != node);
+
+	if(node == chain->head)
+		chain->head = node->next;
+	else
+		node->prev->next = node->next;
+
+	if(node == chain->tail)
+		chain->tail = node->prev;
+	else
+		node->next->prev = node->prev;
+
+	if(0 != chain->tail)
+		chain->tail->data->is_last = true;
+
+	chain->nodes--;
+}
+
+static void chain_delete_node_(FLAC__Metadata_Chain *chain, FLAC__Metadata_Node *node)
+{
+	chain_remove_node_(chain, node);
+	node_delete_(node);
+}
+
+static unsigned chain_calculate_length_(FLAC__Metadata_Chain *chain)
+{
+	const FLAC__Metadata_Node *node;
+	unsigned length = 0;
+	for(node = chain->head; node; node = node->next)
+		length += (FLAC__STREAM_METADATA_HEADER_LENGTH + node->data->length);
+	return length;
+}
+
+static void iterator_insert_node_(FLAC__Metadata_Iterator *iterator, FLAC__Metadata_Node *node)
+{
+	FLAC__ASSERT(0 != node);
+	FLAC__ASSERT(0 != node->data);
+	FLAC__ASSERT(0 != iterator);
+	FLAC__ASSERT(0 != iterator->current);
+	FLAC__ASSERT(0 != iterator->chain);
+	FLAC__ASSERT(0 != iterator->chain->head);
+	FLAC__ASSERT(0 != iterator->chain->tail);
+
+	node->data->is_last = false;
+
+	node->prev = iterator->current->prev;
+	node->next = iterator->current;
+
+	if(0 == node->prev)
+		iterator->chain->head = node;
+	else
+		node->prev->next = node;
+
+	iterator->current->prev = node;
+
+	iterator->chain->nodes++;
+}
+
+static void iterator_insert_node_after_(FLAC__Metadata_Iterator *iterator, FLAC__Metadata_Node *node)
+{
+	FLAC__ASSERT(0 != node);
+	FLAC__ASSERT(0 != node->data);
+	FLAC__ASSERT(0 != iterator);
+	FLAC__ASSERT(0 != iterator->current);
+	FLAC__ASSERT(0 != iterator->chain);
+	FLAC__ASSERT(0 != iterator->chain->head);
+	FLAC__ASSERT(0 != iterator->chain->tail);
+
+	iterator->current->data->is_last = false;
+
+	node->prev = iterator->current;
+	node->next = iterator->current->next;
+
+	if(0 == node->next)
+		iterator->chain->tail = node;
+	else
+		node->next->prev = node;
+
+	node->prev->next = node;
+
+	iterator->chain->tail->data->is_last = true;
+
+	iterator->chain->nodes++;
+}
+
+/* return true iff node and node->next are both padding */
+static FLAC__bool chain_merge_adjacent_padding_(FLAC__Metadata_Chain *chain, FLAC__Metadata_Node *node)
+{
+	if(node->data->type == FLAC__METADATA_TYPE_PADDING && 0 != node->next && node->next->data->type == FLAC__METADATA_TYPE_PADDING) {
+		const unsigned growth = FLAC__STREAM_METADATA_HEADER_LENGTH + node->next->data->length;
+		node->data->length += growth;
+
+		chain_delete_node_(chain, node->next);
+		return true;
+	}
+	else
+		return false;
+}
+
+/* Returns the new length of the chain, or 0 if there was an error. */
+/* WATCHOUT: This can get called multiple times before a write, so
+ * it should still work when this happens.
+ */
+/* WATCHOUT: Make sure to also update the logic in
+ * FLAC__metadata_chain_check_if_tempfile_needed() if the logic here changes.
+ */
+static unsigned chain_prepare_for_write_(FLAC__Metadata_Chain *chain, FLAC__bool use_padding)
+{
+	unsigned current_length = chain_calculate_length_(chain);
+
+	if(use_padding) {
+		/* if the metadata shrank and the last block is padding, we just extend the last padding block */
+		if(current_length < chain->initial_length && chain->tail->data->type == FLAC__METADATA_TYPE_PADDING) {
+			const unsigned delta = chain->initial_length - current_length;
+			chain->tail->data->length += delta;
+			current_length += delta;
+			FLAC__ASSERT(current_length == chain->initial_length);
+		}
+		/* if the metadata shrank more than 4 bytes then there's room to add another padding block */
+		else if(current_length + FLAC__STREAM_METADATA_HEADER_LENGTH <= chain->initial_length) {
+			FLAC__StreamMetadata *padding;
+			FLAC__Metadata_Node *node;
+			if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING))) {
+				chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
+				return 0;
+			}
+			padding->length = chain->initial_length - (FLAC__STREAM_METADATA_HEADER_LENGTH + current_length);
+			if(0 == (node = node_new_())) {
+				FLAC__metadata_object_delete(padding);
+				chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
+				return 0;
+			}
+			node->data = padding;
+			chain_append_node_(chain, node);
+			current_length = chain_calculate_length_(chain);
+			FLAC__ASSERT(current_length == chain->initial_length);
+		}
+		/* if the metadata grew but the last block is padding, try cutting the padding to restore the original length so we don't have to rewrite the whole file */
+		else if(current_length > chain->initial_length) {
+			const unsigned delta = current_length - chain->initial_length;
+			if(chain->tail->data->type == FLAC__METADATA_TYPE_PADDING) {
+				/* if the delta is exactly the size of the last padding block, remove the padding block */
+				if(chain->tail->data->length + FLAC__STREAM_METADATA_HEADER_LENGTH == delta) {
+					chain_delete_node_(chain, chain->tail);
+					current_length = chain_calculate_length_(chain);
+					FLAC__ASSERT(current_length == chain->initial_length);
+				}
+				/* if there is at least 'delta' bytes of padding, trim the padding down */
+				else if(chain->tail->data->length >= delta) {
+					chain->tail->data->length -= delta;
+					current_length -= delta;
+					FLAC__ASSERT(current_length == chain->initial_length);
+				}
+			}
+		}
+	}
+
+	return current_length;
+}
+
+static FLAC__bool chain_read_cb_(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__IOCallback_Tell tell_cb)
+{
+	FLAC__Metadata_Node *node;
+
+	FLAC__ASSERT(0 != chain);
+
+	/* we assume we're already at the beginning of the file */
+
+	switch(seek_to_first_metadata_block_cb_(handle, read_cb, seek_cb)) {
+		case 0:
+			break;
+		case 1:
+			chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR;
+			return false;
+		case 2:
+			chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
+			return false;
+		case 3:
+			chain->status = FLAC__METADATA_CHAIN_STATUS_NOT_A_FLAC_FILE;
+			return false;
+		default:
+			FLAC__ASSERT(0);
+			return false;
+	}
+
+	{
+		FLAC__int64 pos = tell_cb(handle);
+		if(pos < 0) {
+			chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR;
+			return false;
+		}
+		chain->first_offset = (long)pos;
+	}
+
+	{
+		FLAC__bool is_last;
+		FLAC__MetadataType type;
+		unsigned length;
+
+		do {
+			node = node_new_();
+			if(0 == node) {
+				chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
+				return false;
+			}
+
+			if(!read_metadata_block_header_cb_(handle, read_cb, &is_last, &type, &length)) {
+				chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR;
+				return false;
+			}
+
+			node->data = FLAC__metadata_object_new(type);
+			if(0 == node->data) {
+				node_delete_(node);
+				chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
+				return false;
+			}
+
+			node->data->is_last = is_last;
+			node->data->length = length;
+
+			chain->status = get_equivalent_status_(read_metadata_block_data_cb_(handle, read_cb, seek_cb, node->data));
+			if(chain->status != FLAC__METADATA_CHAIN_STATUS_OK) {
+				node_delete_(node);
+				return false;
+			}
+			chain_append_node_(chain, node);
+		} while(!is_last);
+	}
+
+	{
+		FLAC__int64 pos = tell_cb(handle);
+		if(pos < 0) {
+			chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR;
+			return false;
+		}
+		chain->last_offset = (long)pos;
+	}
+
+	chain->initial_length = chain_calculate_length_(chain);
+
+	return true;
+}
+
+static FLAC__bool chain_rewrite_metadata_in_place_cb_(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, FLAC__IOCallback_Seek seek_cb)
+{
+	FLAC__Metadata_Node *node;
+
+	FLAC__ASSERT(0 != chain);
+	FLAC__ASSERT(0 != chain->head);
+
+	if(0 != seek_cb(handle, chain->first_offset, SEEK_SET)) {
+		chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
+		return false;
+	}
+
+	for(node = chain->head; node; node = node->next) {
+		if(!write_metadata_block_header_cb_(handle, write_cb, node->data)) {
+			chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR;
+			return false;
+		}
+		if(!write_metadata_block_data_cb_(handle, write_cb, node->data)) {
+			chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR;
+			return false;
+		}
+	}
+
+	/*FLAC__ASSERT(fflush(), ftell() == chain->last_offset);*/
+
+	chain->status = FLAC__METADATA_CHAIN_STATUS_OK;
+	return true;
+}
+
+static FLAC__bool chain_rewrite_metadata_in_place_(FLAC__Metadata_Chain *chain)
+{
+	FILE *file;
+	FLAC__bool ret;
+
+	FLAC__ASSERT(0 != chain->filename);
+
+	if(0 == (file = fopen(chain->filename, "r+b"))) {
+		chain->status = FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE;
+		return false;
+	}
+
+	/* chain_rewrite_metadata_in_place_cb_() sets chain->status for us */
+	ret = chain_rewrite_metadata_in_place_cb_(chain, (FLAC__IOHandle)file, (FLAC__IOCallback_Write)fwrite, fseek_wrapper_);
+
+	fclose(file);
+
+	return ret;
+}
+
+static FLAC__bool chain_rewrite_file_(FLAC__Metadata_Chain *chain, const char *tempfile_path_prefix)
+{
+	FILE *f, *tempfile;
+	char *tempfilename;
+	FLAC__Metadata_SimpleIteratorStatus status;
+	const FLAC__Metadata_Node *node;
+
+	FLAC__ASSERT(0 != chain);
+	FLAC__ASSERT(0 != chain->filename);
+	FLAC__ASSERT(0 != chain->head);
+
+	/* copy the file prefix (data up to first metadata block */
+	if(0 == (f = fopen(chain->filename, "rb"))) {
+		chain->status = FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE;
+		return false;
+	}
+	if(!open_tempfile_(chain->filename, tempfile_path_prefix, &tempfile, &tempfilename, &status)) {
+		chain->status = get_equivalent_status_(status);
+		cleanup_tempfile_(&tempfile, &tempfilename);
+		return false;
+	}
+	if(!copy_n_bytes_from_file_(f, tempfile, chain->first_offset, &status)) {
+		chain->status = get_equivalent_status_(status);
+		cleanup_tempfile_(&tempfile, &tempfilename);
+		return false;
+	}
+
+	/* write the metadata */
+	for(node = chain->head; node; node = node->next) {
+		if(!write_metadata_block_header_(tempfile, &status, node->data)) {
+			chain->status = get_equivalent_status_(status);
+			return false;
+		}
+		if(!write_metadata_block_data_(tempfile, &status, node->data)) {
+			chain->status = get_equivalent_status_(status);
+			return false;
+		}
+	}
+	/*FLAC__ASSERT(fflush(), ftell() == chain->last_offset);*/
+
+	/* copy the file postfix (everything after the metadata) */
+	if(0 != fseek(f, chain->last_offset, SEEK_SET)) {
+		cleanup_tempfile_(&tempfile, &tempfilename);
+		chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
+		return false;
+	}
+	if(!copy_remaining_bytes_from_file_(f, tempfile, &status)) {
+		cleanup_tempfile_(&tempfile, &tempfilename);
+		chain->status = get_equivalent_status_(status);
+		return false;
+	}
+
+	/* move the tempfile on top of the original */
+	(void)fclose(f);
+	if(!transport_tempfile_(chain->filename, &tempfile, &tempfilename, &status))
+		return false;
+
+	return true;
+}
+
+/* assumes 'handle' is already at beginning of file */
+static FLAC__bool chain_rewrite_file_cb_(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__IOCallback_Eof eof_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write_cb)
+{
+	FLAC__Metadata_SimpleIteratorStatus status;
+	const FLAC__Metadata_Node *node;
+
+	FLAC__ASSERT(0 != chain);
+	FLAC__ASSERT(0 == chain->filename);
+	FLAC__ASSERT(0 != chain->head);
+
+	/* copy the file prefix (data up to first metadata block */
+	if(!copy_n_bytes_from_file_cb_(handle, read_cb, temp_handle, temp_write_cb, chain->first_offset, &status)) {
+		chain->status = get_equivalent_status_(status);
+		return false;
+	}
+
+	/* write the metadata */
+	for(node = chain->head; node; node = node->next) {
+		if(!write_metadata_block_header_cb_(temp_handle, temp_write_cb, node->data)) {
+			chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR;
+			return false;
+		}
+		if(!write_metadata_block_data_cb_(temp_handle, temp_write_cb, node->data)) {
+			chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR;
+			return false;
+		}
+	}
+	/*FLAC__ASSERT(fflush(), ftell() == chain->last_offset);*/
+
+	/* copy the file postfix (everything after the metadata) */
+	if(0 != seek_cb(handle, chain->last_offset, SEEK_SET)) {
+		chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
+		return false;
+	}
+	if(!copy_remaining_bytes_from_file_cb_(handle, read_cb, eof_cb, temp_handle, temp_write_cb, &status)) {
+		chain->status = get_equivalent_status_(status);
+		return false;
+	}
+
+	return true;
+}
+
+FLAC_API FLAC__Metadata_Chain *FLAC__metadata_chain_new()
+{
+	FLAC__Metadata_Chain *chain = (FLAC__Metadata_Chain*)calloc(1, sizeof(FLAC__Metadata_Chain));
+
+	if(0 != chain)
+		chain_init_(chain);
+
+	return chain;
+}
+
+FLAC_API void FLAC__metadata_chain_delete(FLAC__Metadata_Chain *chain)
+{
+	FLAC__ASSERT(0 != chain);
+
+	chain_clear_(chain);
+
+	free(chain);
+}
+
+FLAC_API FLAC__Metadata_ChainStatus FLAC__metadata_chain_status(FLAC__Metadata_Chain *chain)
+{
+	FLAC__Metadata_ChainStatus status;
+
+	FLAC__ASSERT(0 != chain);
+
+	status = chain->status;
+	chain->status = FLAC__METADATA_CHAIN_STATUS_OK;
+	return status;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_chain_read(FLAC__Metadata_Chain *chain, const char *filename)
+{
+	FILE *file;
+	FLAC__bool ret;
+
+	FLAC__ASSERT(0 != chain);
+	FLAC__ASSERT(0 != filename);
+
+	chain_clear_(chain);
+
+	if(0 == (chain->filename = strdup(filename))) {
+		chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
+		return false;
+	}
+
+	if(0 == (file = fopen(filename, "rb"))) {
+		chain->status = FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE;
+		return false;
+	}
+
+	/* chain_read_cb_() sets chain->status for us */
+	ret = chain_read_cb_(chain, file, (FLAC__IOCallback_Read)fread, fseek_wrapper_, ftell_wrapper_);
+
+	fclose(file);
+
+	return ret;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_chain_read_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks)
+{
+	FLAC__ASSERT(0 != chain);
+
+	chain_clear_(chain);
+
+	if (0 == callbacks.read || 0 == callbacks.seek || 0 == callbacks.tell) {
+		chain->status = FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS;
+		return false;
+	}
+
+	/* rewind */
+	if(0 != callbacks.seek(handle, 0, SEEK_SET)) {
+		chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
+		return false;
+	}
+
+	if(!chain_read_cb_(chain, handle, callbacks.read, callbacks.seek, callbacks.tell))
+		return false; /* chain->status is already set by chain_read_cb_ */
+
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_chain_check_if_tempfile_needed(FLAC__Metadata_Chain *chain, FLAC__bool use_padding)
+{
+	/* This does all the same checks that are in chain_prepare_for_write_()
+	 * but doesn't actually alter the chain.  Make sure to update the logic
+	 * here if chain_prepare_for_write_() changes.
+	 */
+	const unsigned current_length = chain_calculate_length_(chain);
+
+	FLAC__ASSERT(0 != chain);
+
+	if(use_padding) {
+		/* if the metadata shrank and the last block is padding, we just extend the last padding block */
+		if(current_length < chain->initial_length && chain->tail->data->type == FLAC__METADATA_TYPE_PADDING)
+			return false;
+		/* if the metadata shrank more than 4 bytes then there's room to add another padding block */
+		else if(current_length + FLAC__STREAM_METADATA_HEADER_LENGTH <= chain->initial_length)
+			return false;
+		/* if the metadata grew but the last block is padding, try cutting the padding to restore the original length so we don't have to rewrite the whole file */
+		else if(current_length > chain->initial_length) {
+			const unsigned delta = current_length - chain->initial_length;
+			if(chain->tail->data->type == FLAC__METADATA_TYPE_PADDING) {
+				/* if the delta is exactly the size of the last padding block, remove the padding block */
+				if(chain->tail->data->length + FLAC__STREAM_METADATA_HEADER_LENGTH == delta)
+					return false;
+				/* if there is at least 'delta' bytes of padding, trim the padding down */
+				else if(chain->tail->data->length >= delta)
+					return false;
+			}
+		}
+	}
+
+	return (current_length != chain->initial_length);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_chain_write(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__bool preserve_file_stats)
+{
+	struct stat stats;
+	const char *tempfile_path_prefix = 0;
+	unsigned current_length;
+
+	FLAC__ASSERT(0 != chain);
+
+	if (0 == chain->filename) {
+		chain->status = FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH;
+		return false;
+	}
+
+	current_length = chain_prepare_for_write_(chain, use_padding);
+
+	/* a return value of 0 means there was an error; chain->status is already set */
+	if (0 == current_length)
+		return false;
+
+	if(preserve_file_stats)
+		get_file_stats_(chain->filename, &stats);
+
+	if(current_length == chain->initial_length) {
+		if(!chain_rewrite_metadata_in_place_(chain))
+			return false;
+	}
+	else {
+		if(!chain_rewrite_file_(chain, tempfile_path_prefix))
+			return false;
+
+		/* recompute lengths and offsets */
+		{
+			const FLAC__Metadata_Node *node;
+			chain->initial_length = current_length;
+			chain->last_offset = chain->first_offset;
+			for(node = chain->head; node; node = node->next)
+				chain->last_offset += (FLAC__STREAM_METADATA_HEADER_LENGTH + node->data->length);
+		}
+	}
+
+	if(preserve_file_stats)
+		set_file_stats_(chain->filename, &stats);
+
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_chain_write_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks)
+{
+	unsigned current_length;
+
+	FLAC__ASSERT(0 != chain);
+
+	if (0 != chain->filename) {
+		chain->status = FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH;
+		return false;
+	}
+
+	if (0 == callbacks.write || 0 == callbacks.seek) {
+		chain->status = FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS;
+		return false;
+	}
+
+	if (FLAC__metadata_chain_check_if_tempfile_needed(chain, use_padding)) {
+		chain->status = FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL;
+		return false;
+	}
+
+	current_length = chain_prepare_for_write_(chain, use_padding);
+
+	/* a return value of 0 means there was an error; chain->status is already set */
+	if (0 == current_length)
+		return false;
+
+	FLAC__ASSERT(current_length == chain->initial_length);
+
+	return chain_rewrite_metadata_in_place_cb_(chain, handle, callbacks.write, callbacks.seek);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_chain_write_with_callbacks_and_tempfile(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks, FLAC__IOHandle temp_handle, FLAC__IOCallbacks temp_callbacks)
+{
+	unsigned current_length;
+
+	FLAC__ASSERT(0 != chain);
+
+	if (0 != chain->filename) {
+		chain->status = FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH;
+		return false;
+	}
+
+	if (0 == callbacks.read || 0 == callbacks.seek || 0 == callbacks.eof) {
+		chain->status = FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS;
+		return false;
+	}
+	if (0 == temp_callbacks.write) {
+		chain->status = FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS;
+		return false;
+	}
+
+	if (!FLAC__metadata_chain_check_if_tempfile_needed(chain, use_padding)) {
+		chain->status = FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL;
+		return false;
+	}
+
+	current_length = chain_prepare_for_write_(chain, use_padding);
+
+	/* a return value of 0 means there was an error; chain->status is already set */
+	if (0 == current_length)
+		return false;
+
+	FLAC__ASSERT(current_length != chain->initial_length);
+
+	/* rewind */
+	if(0 != callbacks.seek(handle, 0, SEEK_SET)) {
+		chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
+		return false;
+	}
+
+	if(!chain_rewrite_file_cb_(chain, handle, callbacks.read, callbacks.seek, callbacks.eof, temp_handle, temp_callbacks.write))
+		return false;
+
+	/* recompute lengths and offsets */
+	{
+		const FLAC__Metadata_Node *node;
+		chain->initial_length = current_length;
+		chain->last_offset = chain->first_offset;
+		for(node = chain->head; node; node = node->next)
+			chain->last_offset += (FLAC__STREAM_METADATA_HEADER_LENGTH + node->data->length);
+	}
+
+	return true;
+}
+
+FLAC_API void FLAC__metadata_chain_merge_padding(FLAC__Metadata_Chain *chain)
+{
+	FLAC__Metadata_Node *node;
+
+	FLAC__ASSERT(0 != chain);
+
+	for(node = chain->head; node; ) {
+		if(!chain_merge_adjacent_padding_(chain, node))
+			node = node->next;
+	}
+}
+
+FLAC_API void FLAC__metadata_chain_sort_padding(FLAC__Metadata_Chain *chain)
+{
+	FLAC__Metadata_Node *node, *save;
+	unsigned i;
+
+	FLAC__ASSERT(0 != chain);
+
+	/*
+	 * Don't try and be too smart... this simple algo is good enough for
+	 * the small number of nodes that we deal with.
+	 */
+	for(i = 0, node = chain->head; i < chain->nodes; i++) {
+		if(node->data->type == FLAC__METADATA_TYPE_PADDING) {
+			save = node->next;
+			chain_remove_node_(chain, node);
+			chain_append_node_(chain, node);
+			node = save;
+		}
+		else {
+			node = node->next;
+		}
+	}
+
+	FLAC__metadata_chain_merge_padding(chain);
+}
+
+
+FLAC_API FLAC__Metadata_Iterator *FLAC__metadata_iterator_new()
+{
+	FLAC__Metadata_Iterator *iterator = (FLAC__Metadata_Iterator*)calloc(1, sizeof(FLAC__Metadata_Iterator));
+
+	/* calloc() implies:
+		iterator->current = 0;
+		iterator->chain = 0;
+	*/
+
+	return iterator;
+}
+
+FLAC_API void FLAC__metadata_iterator_delete(FLAC__Metadata_Iterator *iterator)
+{
+	FLAC__ASSERT(0 != iterator);
+
+	free(iterator);
+}
+
+FLAC_API void FLAC__metadata_iterator_init(FLAC__Metadata_Iterator *iterator, FLAC__Metadata_Chain *chain)
+{
+	FLAC__ASSERT(0 != iterator);
+	FLAC__ASSERT(0 != chain);
+	FLAC__ASSERT(0 != chain->head);
+
+	iterator->chain = chain;
+	iterator->current = chain->head;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_iterator_next(FLAC__Metadata_Iterator *iterator)
+{
+	FLAC__ASSERT(0 != iterator);
+
+	if(0 == iterator->current || 0 == iterator->current->next)
+		return false;
+
+	iterator->current = iterator->current->next;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_iterator_prev(FLAC__Metadata_Iterator *iterator)
+{
+	FLAC__ASSERT(0 != iterator);
+
+	if(0 == iterator->current || 0 == iterator->current->prev)
+		return false;
+
+	iterator->current = iterator->current->prev;
+	return true;
+}
+
+FLAC_API FLAC__MetadataType FLAC__metadata_iterator_get_block_type(const FLAC__Metadata_Iterator *iterator)
+{
+	FLAC__ASSERT(0 != iterator);
+	FLAC__ASSERT(0 != iterator->current);
+	FLAC__ASSERT(0 != iterator->current->data);
+
+	return iterator->current->data->type;
+}
+
+FLAC_API FLAC__StreamMetadata *FLAC__metadata_iterator_get_block(FLAC__Metadata_Iterator *iterator)
+{
+	FLAC__ASSERT(0 != iterator);
+	FLAC__ASSERT(0 != iterator->current);
+
+	return iterator->current->data;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_iterator_set_block(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block)
+{
+	FLAC__ASSERT(0 != iterator);
+	FLAC__ASSERT(0 != block);
+	return FLAC__metadata_iterator_delete_block(iterator, false) && FLAC__metadata_iterator_insert_block_after(iterator, block);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_iterator_delete_block(FLAC__Metadata_Iterator *iterator, FLAC__bool replace_with_padding)
+{
+	FLAC__Metadata_Node *save;
+
+	FLAC__ASSERT(0 != iterator);
+	FLAC__ASSERT(0 != iterator->current);
+
+	if(0 == iterator->current->prev) {
+		FLAC__ASSERT(iterator->current->data->type == FLAC__METADATA_TYPE_STREAMINFO);
+		return false;
+	}
+
+	save = iterator->current->prev;
+
+	if(replace_with_padding) {
+		FLAC__metadata_object_delete_data(iterator->current->data);
+		iterator->current->data->type = FLAC__METADATA_TYPE_PADDING;
+	}
+	else {
+		chain_delete_node_(iterator->chain, iterator->current);
+	}
+
+	iterator->current = save;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_iterator_insert_block_before(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block)
+{
+	FLAC__Metadata_Node *node;
+
+	FLAC__ASSERT(0 != iterator);
+	FLAC__ASSERT(0 != iterator->current);
+	FLAC__ASSERT(0 != block);
+
+	if(block->type == FLAC__METADATA_TYPE_STREAMINFO)
+		return false;
+
+	if(0 == iterator->current->prev) {
+		FLAC__ASSERT(iterator->current->data->type == FLAC__METADATA_TYPE_STREAMINFO);
+		return false;
+	}
+
+	if(0 == (node = node_new_()))
+		return false;
+
+	node->data = block;
+	iterator_insert_node_(iterator, node);
+	iterator->current = node;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_iterator_insert_block_after(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block)
+{
+	FLAC__Metadata_Node *node;
+
+	FLAC__ASSERT(0 != iterator);
+	FLAC__ASSERT(0 != iterator->current);
+	FLAC__ASSERT(0 != block);
+
+	if(block->type == FLAC__METADATA_TYPE_STREAMINFO)
+		return false;
+
+	if(0 == (node = node_new_()))
+		return false;
+
+	node->data = block;
+	iterator_insert_node_after_(iterator, node);
+	iterator->current = node;
+	return true;
+}
+
+
+/****************************************************************************
+ *
+ * Local function definitions
+ *
+ ***************************************************************************/
+
+void pack_uint32_(FLAC__uint32 val, FLAC__byte *b, unsigned bytes)
+{
+	unsigned i;
+
+	b += bytes;
+
+	for(i = 0; i < bytes; i++) {
+		*(--b) = (FLAC__byte)(val & 0xff);
+		val >>= 8;
+	}
+}
+
+void pack_uint32_little_endian_(FLAC__uint32 val, FLAC__byte *b, unsigned bytes)
+{
+	unsigned i;
+
+	for(i = 0; i < bytes; i++) {
+		*(b++) = (FLAC__byte)(val & 0xff);
+		val >>= 8;
+	}
+}
+
+void pack_uint64_(FLAC__uint64 val, FLAC__byte *b, unsigned bytes)
+{
+	unsigned i;
+
+	b += bytes;
+
+	for(i = 0; i < bytes; i++) {
+		*(--b) = (FLAC__byte)(val & 0xff);
+		val >>= 8;
+	}
+}
+
+FLAC__uint32 unpack_uint32_(FLAC__byte *b, unsigned bytes)
+{
+	FLAC__uint32 ret = 0;
+	unsigned i;
+
+	for(i = 0; i < bytes; i++)
+		ret = (ret << 8) | (FLAC__uint32)(*b++);
+
+	return ret;
+}
+
+FLAC__uint32 unpack_uint32_little_endian_(FLAC__byte *b, unsigned bytes)
+{
+	FLAC__uint32 ret = 0;
+	unsigned i;
+
+	b += bytes;
+
+	for(i = 0; i < bytes; i++)
+		ret = (ret << 8) | (FLAC__uint32)(*--b);
+
+	return ret;
+}
+
+FLAC__uint64 unpack_uint64_(FLAC__byte *b, unsigned bytes)
+{
+	FLAC__uint64 ret = 0;
+	unsigned i;
+
+	for(i = 0; i < bytes; i++)
+		ret = (ret << 8) | (FLAC__uint64)(*b++);
+
+	return ret;
+}
+
+FLAC__bool read_metadata_block_header_(FLAC__Metadata_SimpleIterator *iterator)
+{
+	FLAC__ASSERT(0 != iterator);
+	FLAC__ASSERT(0 != iterator->file);
+
+	if(!read_metadata_block_header_cb_((FLAC__IOHandle)iterator->file, (FLAC__IOCallback_Read)fread, &iterator->is_last, &iterator->type, &iterator->length)) {
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+		return false;
+	}
+
+	return true;
+}
+
+FLAC__bool read_metadata_block_data_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block)
+{
+	FLAC__ASSERT(0 != iterator);
+	FLAC__ASSERT(0 != iterator->file);
+
+	iterator->status = read_metadata_block_data_cb_((FLAC__IOHandle)iterator->file, (FLAC__IOCallback_Read)fread, fseek_wrapper_, block);
+
+	return (iterator->status == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK);
+}
+
+FLAC__bool read_metadata_block_header_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__bool *is_last, FLAC__MetadataType *type, unsigned *length)
+{
+	FLAC__byte raw_header[FLAC__STREAM_METADATA_HEADER_LENGTH];
+
+	if(read_cb(raw_header, 1, FLAC__STREAM_METADATA_HEADER_LENGTH, handle) != FLAC__STREAM_METADATA_HEADER_LENGTH)
+		return false;
+
+	*is_last = raw_header[0] & 0x80? true : false;
+	*type = (FLAC__MetadataType)(raw_header[0] & 0x7f);
+	*length = unpack_uint32_(raw_header + 1, 3);
+
+	/* Note that we don't check:
+	 *    if(iterator->type >= FLAC__METADATA_TYPE_UNDEFINED)
+	 * we just will read in an opaque block
+	 */
+
+	return true;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata *block)
+{
+	switch(block->type) {
+		case FLAC__METADATA_TYPE_STREAMINFO:
+			return read_metadata_block_data_streaminfo_cb_(handle, read_cb, &block->data.stream_info);
+		case FLAC__METADATA_TYPE_PADDING:
+			return read_metadata_block_data_padding_cb_(handle, seek_cb, &block->data.padding, block->length);
+		case FLAC__METADATA_TYPE_APPLICATION:
+			return read_metadata_block_data_application_cb_(handle, read_cb, &block->data.application, block->length);
+		case FLAC__METADATA_TYPE_SEEKTABLE:
+			return read_metadata_block_data_seektable_cb_(handle, read_cb, &block->data.seek_table, block->length);
+		case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+			return read_metadata_block_data_vorbis_comment_cb_(handle, read_cb, &block->data.vorbis_comment);
+		case FLAC__METADATA_TYPE_CUESHEET:
+			return read_metadata_block_data_cuesheet_cb_(handle, read_cb, &block->data.cue_sheet);
+		default:
+			return read_metadata_block_data_unknown_cb_(handle, read_cb, &block->data.unknown, block->length);
+	}
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_streaminfo_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_StreamInfo *block)
+{
+	FLAC__byte buffer[FLAC__STREAM_METADATA_STREAMINFO_LENGTH], *b;
+
+	if(read_cb(buffer, 1, FLAC__STREAM_METADATA_STREAMINFO_LENGTH, handle) != FLAC__STREAM_METADATA_STREAMINFO_LENGTH)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+
+	b = buffer;
+
+	/* we are using hardcoded numbers for simplicity but we should
+	 * probably eventually write a bit-level unpacker and use the
+	 * _STREAMINFO_ constants.
+	 */
+	block->min_blocksize = unpack_uint32_(b, 2); b += 2;
+	block->max_blocksize = unpack_uint32_(b, 2); b += 2;
+	block->min_framesize = unpack_uint32_(b, 3); b += 3;
+	block->max_framesize = unpack_uint32_(b, 3); b += 3;
+	block->sample_rate = (unpack_uint32_(b, 2) << 4) | ((unsigned)(b[2] & 0xf0) >> 4);
+	block->channels = (unsigned)((b[2] & 0x0e) >> 1) + 1;
+	block->bits_per_sample = ((((unsigned)(b[2] & 0x01)) << 4) | (((unsigned)(b[3] & 0xf0)) >> 4)) + 1;
+	block->total_samples = (((FLAC__uint64)(b[3] & 0x0f)) << 32) | unpack_uint64_(b+4, 4);
+	memcpy(block->md5sum, b+8, 16);
+
+	return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_padding_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata_Padding *block, unsigned block_length)
+{
+	(void)block; /* nothing to do; we don't care about reading the padding bytes */
+
+	if(0 != seek_cb(handle, block_length, SEEK_CUR))
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+
+	return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_application_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Application *block, unsigned block_length)
+{
+	const unsigned id_bytes = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8;
+
+	if(read_cb(block->id, 1, id_bytes, handle) != id_bytes)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+
+	block_length -= id_bytes;
+
+	if(block_length == 0) {
+		block->data = 0;
+	}
+	else {
+		if(0 == (block->data = (FLAC__byte*)malloc(block_length)))
+			return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+		if(read_cb(block->data, 1, block_length, handle) != block_length)
+			return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	}
+
+	return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_seektable_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_SeekTable *block, unsigned block_length)
+{
+	unsigned i;
+	FLAC__byte buffer[FLAC__STREAM_METADATA_SEEKPOINT_LENGTH];
+
+	FLAC__ASSERT(block_length % FLAC__STREAM_METADATA_SEEKPOINT_LENGTH == 0);
+
+	block->num_points = block_length / FLAC__STREAM_METADATA_SEEKPOINT_LENGTH;
+
+	if(block->num_points == 0)
+		block->points = 0;
+	else if(0 == (block->points = (FLAC__StreamMetadata_SeekPoint*)malloc(block->num_points * sizeof(FLAC__StreamMetadata_SeekPoint))))
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+	for(i = 0; i < block->num_points; i++) {
+		if(read_cb(buffer, 1, FLAC__STREAM_METADATA_SEEKPOINT_LENGTH, handle) != FLAC__STREAM_METADATA_SEEKPOINT_LENGTH)
+			return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+		/* some MAGIC NUMBERs here */
+		block->points[i].sample_number = unpack_uint64_(buffer, 8);
+		block->points[i].stream_offset = unpack_uint64_(buffer+8, 8);
+		block->points[i].frame_samples = unpack_uint32_(buffer+16, 2);
+	}
+
+	return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_entry_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_VorbisComment_Entry *entry)
+{
+	const unsigned entry_length_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8;
+	FLAC__byte buffer[4]; /* magic number is asserted below */
+
+	FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8 == 4);
+
+	if(read_cb(buffer, 1, entry_length_len, handle) != entry_length_len)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	entry->length = unpack_uint32_little_endian_(buffer, entry_length_len);
+
+	if(0 != entry->entry)
+		free(entry->entry);
+
+	if(entry->length == 0) {
+		entry->entry = 0;
+	}
+	else {
+		if(0 == (entry->entry = (FLAC__byte*)malloc(entry->length)))
+			return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+		if(read_cb(entry->entry, 1, entry->length, handle) != entry->length)
+			return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	}
+
+	return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_VorbisComment *block)
+{
+	unsigned i;
+	FLAC__Metadata_SimpleIteratorStatus status;
+	const unsigned num_comments_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN / 8;
+	FLAC__byte buffer[4]; /* magic number is asserted below */
+
+	FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN / 8 == 4);
+
+	if(FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK != (status = read_metadata_block_data_vorbis_comment_entry_cb_(handle, read_cb, &(block->vendor_string))))
+		return status;
+
+	if(read_cb(buffer, 1, num_comments_len, handle) != num_comments_len)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	block->num_comments = unpack_uint32_little_endian_(buffer, num_comments_len);
+
+	if(block->num_comments == 0) {
+		block->comments = 0;
+	}
+	else if(0 == (block->comments = (FLAC__StreamMetadata_VorbisComment_Entry*)calloc(block->num_comments, sizeof(FLAC__StreamMetadata_VorbisComment_Entry))))
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+	for(i = 0; i < block->num_comments; i++) {
+		if(FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK != (status = read_metadata_block_data_vorbis_comment_entry_cb_(handle, read_cb, block->comments + i)))
+			return status;
+	}
+
+	return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_track_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_CueSheet_Track *track)
+{
+	unsigned i, len;
+	FLAC__byte buffer[32]; /* asserted below that this is big enough */
+
+	FLAC__ASSERT(sizeof(buffer) >= sizeof(FLAC__uint64));
+	FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN/8);
+	FLAC__ASSERT(sizeof(buffer) >= (FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN) / 8);
+
+	FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN % 8 == 0);
+	len = FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN / 8;
+	if(read_cb(buffer, 1, len, handle) != len)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	track->offset = unpack_uint64_(buffer, len);
+
+	FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN % 8 == 0);
+	len = FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN / 8;
+	if(read_cb(buffer, 1, len, handle) != len)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	track->number = (FLAC__byte)unpack_uint32_(buffer, len);
+
+	FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN % 8 == 0);
+	len = FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN / 8;
+	if(read_cb(track->isrc, 1, len, handle) != len)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+
+	FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN) % 8 == 0);
+	len = (FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN) / 8;
+	if(read_cb(buffer, 1, len, handle) != len)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN == 1);
+	FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN == 1);
+	track->type = buffer[0] >> 7;
+	track->pre_emphasis = (buffer[0] >> 6) & 1;
+
+	FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN % 8 == 0);
+	len = FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN / 8;
+	if(read_cb(buffer, 1, len, handle) != len)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	track->num_indices = (FLAC__byte)unpack_uint32_(buffer, len);
+
+	if(track->num_indices == 0) {
+		track->indices = 0;
+	}
+	else if(0 == (track->indices = (FLAC__StreamMetadata_CueSheet_Index*)calloc(track->num_indices, sizeof(FLAC__StreamMetadata_CueSheet_Index))))
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+	for(i = 0; i < track->num_indices; i++) {
+		FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN % 8 == 0);
+		len = FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN / 8;
+		if(read_cb(buffer, 1, len, handle) != len)
+			return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+		track->indices[i].offset = unpack_uint64_(buffer, len);
+
+		FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN % 8 == 0);
+		len = FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN / 8;
+		if(read_cb(buffer, 1, len, handle) != len)
+			return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+		track->indices[i].number = (FLAC__byte)unpack_uint32_(buffer, len);
+
+		FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN % 8 == 0);
+		len = FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN / 8;
+		if(read_cb(buffer, 1, len, handle) != len)
+			return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	}
+
+	return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_CueSheet *block)
+{
+	unsigned i, len;
+	FLAC__Metadata_SimpleIteratorStatus status;
+	FLAC__byte buffer[1024]; /* MSVC needs a constant expression so we put a magic number and assert */
+
+	FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN)/8 <= sizeof(buffer));
+	FLAC__ASSERT(sizeof(FLAC__uint64) <= sizeof(buffer));
+
+	FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN % 8 == 0);
+	len = FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN / 8;
+	if(read_cb(block->media_catalog_number, 1, len, handle) != len)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+
+	FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN % 8 == 0);
+	len = FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN / 8;
+	if(read_cb(buffer, 1, len, handle) != len)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	block->lead_in = unpack_uint64_(buffer, len);
+
+	FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN) % 8 == 0);
+	len = (FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN) / 8;
+	if(read_cb(buffer, 1, len, handle) != len)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	block->is_cd = buffer[0]&0x80? true : false;
+
+	FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN % 8 == 0);
+	len = FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN / 8;
+	if(read_cb(buffer, 1, len, handle) != len)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	block->num_tracks = unpack_uint32_(buffer, len);
+
+	if(block->num_tracks == 0) {
+		block->tracks = 0;
+	}
+	else if(0 == (block->tracks = (FLAC__StreamMetadata_CueSheet_Track*)calloc(block->num_tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track))))
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+	for(i = 0; i < block->num_tracks; i++) {
+		if(FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK != (status = read_metadata_block_data_cuesheet_track_cb_(handle, read_cb, block->tracks + i)))
+			return status;
+	}
+
+	return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_unknown_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Unknown *block, unsigned block_length)
+{
+	if(block_length == 0) {
+		block->data = 0;
+	}
+	else {
+		if(0 == (block->data = (FLAC__byte*)malloc(block_length)))
+			return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+		if(read_cb(block->data, 1, block_length, handle) != block_length)
+			return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	}
+
+	return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__bool write_metadata_block_header_(FILE *file, FLAC__Metadata_SimpleIteratorStatus *status, const FLAC__StreamMetadata *block)
+{
+	FLAC__ASSERT(0 != file);
+	FLAC__ASSERT(0 != status);
+
+	if(!write_metadata_block_header_cb_((FLAC__IOHandle)file, (FLAC__IOCallback_Write)fwrite, block)) {
+		*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+		return false;
+	}
+
+	return true;
+}
+
+FLAC__bool write_metadata_block_data_(FILE *file, FLAC__Metadata_SimpleIteratorStatus *status, const FLAC__StreamMetadata *block)
+{
+	FLAC__ASSERT(0 != file);
+	FLAC__ASSERT(0 != status);
+
+	if (write_metadata_block_data_cb_((FLAC__IOHandle)file, (FLAC__IOCallback_Write)fwrite, block)) {
+		*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+		return true;
+	}
+	else {
+		*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+		return false;
+	}
+}
+
+FLAC__bool write_metadata_block_header_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata *block)
+{
+	FLAC__byte buffer[FLAC__STREAM_METADATA_HEADER_LENGTH];
+
+	FLAC__ASSERT(block->length < (1u << FLAC__STREAM_METADATA_LENGTH_LEN));
+
+	buffer[0] = (block->is_last? 0x80 : 0) | (FLAC__byte)block->type;
+	pack_uint32_(block->length, buffer + 1, 3);
+
+	if(write_cb(buffer, 1, FLAC__STREAM_METADATA_HEADER_LENGTH, handle) != FLAC__STREAM_METADATA_HEADER_LENGTH)
+		return false;
+
+	return true;
+}
+
+FLAC__bool write_metadata_block_data_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata *block)
+{
+	FLAC__ASSERT(0 != block);
+
+	switch(block->type) {
+		case FLAC__METADATA_TYPE_STREAMINFO:
+			return write_metadata_block_data_streaminfo_cb_(handle, write_cb, &block->data.stream_info);
+		case FLAC__METADATA_TYPE_PADDING:
+			return write_metadata_block_data_padding_cb_(handle, write_cb, &block->data.padding, block->length);
+		case FLAC__METADATA_TYPE_APPLICATION:
+			return write_metadata_block_data_application_cb_(handle, write_cb, &block->data.application, block->length);
+		case FLAC__METADATA_TYPE_SEEKTABLE:
+			return write_metadata_block_data_seektable_cb_(handle, write_cb, &block->data.seek_table);
+		case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+			return write_metadata_block_data_vorbis_comment_cb_(handle, write_cb, &block->data.vorbis_comment);
+		case FLAC__METADATA_TYPE_CUESHEET:
+			return write_metadata_block_data_cuesheet_cb_(handle, write_cb, &block->data.cue_sheet);
+		default:
+			return write_metadata_block_data_unknown_cb_(handle, write_cb, &block->data.unknown, block->length);
+	}
+}
+
+FLAC__bool write_metadata_block_data_streaminfo_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_StreamInfo *block)
+{
+	FLAC__byte buffer[FLAC__STREAM_METADATA_STREAMINFO_LENGTH];
+	const unsigned channels1 = block->channels - 1;
+	const unsigned bps1 = block->bits_per_sample - 1;
+
+	/* we are using hardcoded numbers for simplicity but we should
+	 * probably eventually write a bit-level packer and use the
+	 * _STREAMINFO_ constants.
+	 */
+	pack_uint32_(block->min_blocksize, buffer, 2);
+	pack_uint32_(block->max_blocksize, buffer+2, 2);
+	pack_uint32_(block->min_framesize, buffer+4, 3);
+	pack_uint32_(block->max_framesize, buffer+7, 3);
+	buffer[10] = (block->sample_rate >> 12) & 0xff;
+	buffer[11] = (block->sample_rate >> 4) & 0xff;
+	buffer[12] = ((block->sample_rate & 0x0f) << 4) | (channels1 << 1) | (bps1 >> 4);
+	buffer[13] = (FLAC__byte)(((bps1 & 0x0f) << 4) | ((block->total_samples >> 32) & 0x0f));
+	pack_uint32_((FLAC__uint32)block->total_samples, buffer+14, 4);
+	memcpy(buffer+18, block->md5sum, 16);
+
+	if(write_cb(buffer, 1, FLAC__STREAM_METADATA_STREAMINFO_LENGTH, handle) != FLAC__STREAM_METADATA_STREAMINFO_LENGTH)
+		return false;
+
+	return true;
+}
+
+FLAC__bool write_metadata_block_data_padding_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Padding *block, unsigned block_length)
+{
+	unsigned i, n = block_length;
+	FLAC__byte buffer[1024];
+
+	(void)block;
+
+	memset(buffer, 0, 1024);
+
+	for(i = 0; i < n/1024; i++)
+		if(write_cb(buffer, 1, 1024, handle) != 1024)
+			return false;
+
+	n %= 1024;
+
+	if(write_cb(buffer, 1, n, handle) != n)
+		return false;
+
+	return true;
+}
+
+FLAC__bool write_metadata_block_data_application_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Application *block, unsigned block_length)
+{
+	const unsigned id_bytes = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8;
+
+	if(write_cb(block->id, 1, id_bytes, handle) != id_bytes)
+		return false;
+
+	block_length -= id_bytes;
+
+	if(write_cb(block->data, 1, block_length, handle) != block_length)
+		return false;
+
+	return true;
+}
+
+FLAC__bool write_metadata_block_data_seektable_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_SeekTable *block)
+{
+	unsigned i;
+	FLAC__byte buffer[FLAC__STREAM_METADATA_SEEKPOINT_LENGTH];
+
+	for(i = 0; i < block->num_points; i++) {
+		/* some MAGIC NUMBERs here */
+		pack_uint64_(block->points[i].sample_number, buffer, 8);
+		pack_uint64_(block->points[i].stream_offset, buffer+8, 8);
+		pack_uint32_(block->points[i].frame_samples, buffer+16, 2);
+		if(write_cb(buffer, 1, FLAC__STREAM_METADATA_SEEKPOINT_LENGTH, handle) != FLAC__STREAM_METADATA_SEEKPOINT_LENGTH)
+			return false;
+	}
+
+	return true;
+}
+
+FLAC__bool write_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_VorbisComment *block)
+{
+	unsigned i;
+	const unsigned entry_length_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8;
+	const unsigned num_comments_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN / 8;
+	FLAC__byte buffer[4]; /* magic number is asserted below */
+
+	FLAC__ASSERT(max(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN, FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN) / 8 == 4);
+
+	pack_uint32_little_endian_(block->vendor_string.length, buffer, entry_length_len);
+	if(write_cb(buffer, 1, entry_length_len, handle) != entry_length_len)
+		return false;
+	if(write_cb(block->vendor_string.entry, 1, block->vendor_string.length, handle) != block->vendor_string.length)
+		return false;
+
+	pack_uint32_little_endian_(block->num_comments, buffer, num_comments_len);
+	if(write_cb(buffer, 1, num_comments_len, handle) != num_comments_len)
+		return false;
+
+	for(i = 0; i < block->num_comments; i++) {
+		pack_uint32_little_endian_(block->comments[i].length, buffer, entry_length_len);
+		if(write_cb(buffer, 1, entry_length_len, handle) != entry_length_len)
+			return false;
+		if(write_cb(block->comments[i].entry, 1, block->comments[i].length, handle) != block->comments[i].length)
+			return false;
+	}
+
+	return true;
+}
+
+FLAC__bool write_metadata_block_data_cuesheet_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_CueSheet *block)
+{
+	unsigned i, j, len;
+	FLAC__byte buffer[1024]; /* asserted below that this is big enough */
+
+	FLAC__ASSERT(sizeof(buffer) >= sizeof(FLAC__uint64));
+	FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN/8);
+	FLAC__ASSERT(sizeof(buffer) >= (FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN)/8);
+	FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN/8);
+
+	FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN % 8 == 0);
+	len = FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN / 8;
+	if(write_cb(block->media_catalog_number, 1, len, handle) != len)
+		return false;
+
+	FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN % 8 == 0);
+	len = FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN / 8;
+	pack_uint64_(block->lead_in, buffer, len);
+	if(write_cb(buffer, 1, len, handle) != len)
+		return false;
+
+	FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN) % 8 == 0);
+	len = (FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN) / 8;
+	memset(buffer, 0, len);
+	if(block->is_cd)
+		buffer[0] |= 0x80;
+	if(write_cb(buffer, 1, len, handle) != len)
+		return false;
+
+	FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN % 8 == 0);
+	len = FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN / 8;
+	pack_uint32_(block->num_tracks, buffer, len);
+	if(write_cb(buffer, 1, len, handle) != len)
+		return false;
+
+	for(i = 0; i < block->num_tracks; i++) {
+		FLAC__StreamMetadata_CueSheet_Track *track = block->tracks + i;
+
+		FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN % 8 == 0);
+		len = FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN / 8;
+		pack_uint64_(track->offset, buffer, len);
+		if(write_cb(buffer, 1, len, handle) != len)
+			return false;
+
+		FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN % 8 == 0);
+		len = FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN / 8;
+		pack_uint32_(track->number, buffer, len);
+		if(write_cb(buffer, 1, len, handle) != len)
+			return false;
+
+		FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN % 8 == 0);
+		len = FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN / 8;
+		if(write_cb(track->isrc, 1, len, handle) != len)
+			return false;
+
+		FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN) % 8 == 0);
+		len = (FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN) / 8;
+		memset(buffer, 0, len);
+		buffer[0] = (track->type << 7) | (track->pre_emphasis << 6);
+		if(write_cb(buffer, 1, len, handle) != len)
+			return false;
+
+		FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN % 8 == 0);
+		len = FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN / 8;
+		pack_uint32_(track->num_indices, buffer, len);
+		if(write_cb(buffer, 1, len, handle) != len)
+			return false;
+
+		for(j = 0; j < track->num_indices; j++) {
+			FLAC__StreamMetadata_CueSheet_Index *index = track->indices + j;
+
+			FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN % 8 == 0);
+			len = FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN / 8;
+			pack_uint64_(index->offset, buffer, len);
+			if(write_cb(buffer, 1, len, handle) != len)
+				return false;
+
+			FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN % 8 == 0);
+			len = FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN / 8;
+			pack_uint32_(index->number, buffer, len);
+			if(write_cb(buffer, 1, len, handle) != len)
+				return false;
+
+			FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN % 8 == 0);
+			len = FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN / 8;
+			memset(buffer, 0, len);
+			if(write_cb(buffer, 1, len, handle) != len)
+				return false;
+		}
+	}
+
+	return true;
+}
+
+FLAC__bool write_metadata_block_data_unknown_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Unknown *block, unsigned block_length)
+{
+	if(write_cb(block->data, 1, block_length, handle) != block_length)
+		return false;
+
+	return true;
+}
+
+FLAC__bool write_metadata_block_stationary_(FLAC__Metadata_SimpleIterator *iterator, const FLAC__StreamMetadata *block)
+{
+	if(0 != fseek(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) {
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+		return false;
+	}
+
+	if(!write_metadata_block_header_(iterator->file, &iterator->status, block))
+		return false;
+
+	if(!write_metadata_block_data_(iterator->file, &iterator->status, block))
+		return false;
+
+	if(0 != fseek(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) {
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+		return false;
+	}
+
+	return read_metadata_block_header_(iterator);
+}
+
+FLAC__bool write_metadata_block_stationary_with_padding_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, unsigned padding_length, FLAC__bool padding_is_last)
+{
+	FLAC__StreamMetadata *padding;
+
+	if(0 != fseek(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) {
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+		return false;
+	}
+
+	block->is_last = false;
+
+	if(!write_metadata_block_header_(iterator->file, &iterator->status, block))
+		return false;
+
+	if(!write_metadata_block_data_(iterator->file, &iterator->status, block))
+		return false;
+
+	if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+	padding->is_last = padding_is_last;
+	padding->length = padding_length;
+
+	if(!write_metadata_block_header_(iterator->file, &iterator->status, padding)) {
+		FLAC__metadata_object_delete(padding);
+		return false;
+	}
+
+	if(!write_metadata_block_data_(iterator->file, &iterator->status, padding)) {
+		FLAC__metadata_object_delete(padding);
+		return false;
+	}
+
+	FLAC__metadata_object_delete(padding);
+
+	if(0 != fseek(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) {
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+		return false;
+	}
+
+	return read_metadata_block_header_(iterator);
+}
+
+FLAC__bool rewrite_whole_file_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool append)
+{
+	FILE *tempfile;
+	char *tempfilename;
+	int fixup_is_last_code = 0; /* 0 => no need to change any is_last flags */
+	long fixup_is_last_flag_offset = -1;
+
+	FLAC__ASSERT(0 != block || append == false);
+
+	if(iterator->is_last) {
+		if(append) {
+			fixup_is_last_code = 1; /* 1 => clear the is_last flag at the following offset */
+			fixup_is_last_flag_offset = iterator->offset[iterator->depth];
+		}
+		else if(0 == block) {
+			simple_iterator_push_(iterator);
+			if(!FLAC__metadata_simple_iterator_prev(iterator)) {
+				(void)simple_iterator_pop_(iterator);
+				return false;
+			}
+			fixup_is_last_code = -1; /* -1 => set the is_last the flag at the following offset */
+			fixup_is_last_flag_offset = iterator->offset[iterator->depth];
+			if(!simple_iterator_pop_(iterator))
+				return false;
+		}
+	}
+
+	if(!simple_iterator_copy_file_prefix_(iterator, &tempfile, &tempfilename, append))
+		return false;
+
+	if(0 != block) {
+		if(!write_metadata_block_header_(tempfile, &iterator->status, block)) {
+			cleanup_tempfile_(&tempfile, &tempfilename);
+			return false;
+		}
+
+		if(!write_metadata_block_data_(tempfile, &iterator->status, block)) {
+			cleanup_tempfile_(&tempfile, &tempfilename);
+			return false;
+		}
+	}
+
+	if(!simple_iterator_copy_file_postfix_(iterator, &tempfile, &tempfilename, fixup_is_last_code, fixup_is_last_flag_offset, block==0))
+		return false;
+
+	if(append)
+		return FLAC__metadata_simple_iterator_next(iterator);
+
+	return true;
+}
+
+void simple_iterator_push_(FLAC__Metadata_SimpleIterator *iterator)
+{
+	FLAC__ASSERT(iterator->depth+1 < SIMPLE_ITERATOR_MAX_PUSH_DEPTH);
+	iterator->offset[iterator->depth+1] = iterator->offset[iterator->depth];
+	iterator->depth++;
+}
+
+FLAC__bool simple_iterator_pop_(FLAC__Metadata_SimpleIterator *iterator)
+{
+	FLAC__ASSERT(iterator->depth > 0);
+	iterator->depth--;
+	if(0 != fseek(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) {
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+		return false;
+	}
+
+	return read_metadata_block_header_(iterator);
+}
+
+/* return meanings:
+ * 0: ok
+ * 1: read error
+ * 2: seek error
+ * 3: not a FLAC file
+ */
+unsigned seek_to_first_metadata_block_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb)
+{
+	FLAC__byte buffer[4];
+	size_t n;
+	unsigned i;
+
+	FLAC__ASSERT(FLAC__STREAM_SYNC_LENGTH == 4);
+
+	/* skip any id3v2 tag */
+	errno = 0;
+	n = read_cb(buffer, 1, 4, handle);
+	if(errno)
+		return 1;
+	else if(n != 4)
+		return 3;
+	else if(0 == memcmp(buffer, "ID3", 3)) {
+		unsigned tag_length = 0;
+
+		/* skip to the tag length */
+		if(seek_cb(handle, 2, SEEK_CUR) < 0)
+			return 2;
+
+		/* read the length */
+		for(i = 0; i < 4; i++) {
+			if(read_cb(buffer, 1, 1, handle) < 1 || buffer[0] & 0x80)
+				return 1;
+			tag_length <<= 7;
+			tag_length |= (buffer[0] & 0x7f);
+		}
+
+		/* skip the rest of the tag */
+		if(seek_cb(handle, tag_length, SEEK_CUR) < 0)
+			return 2;
+
+		/* read the stream sync code */
+		errno = 0;
+		n = read_cb(buffer, 1, 4, handle);
+		if(errno)
+			return 1;
+		else if(n != 4)
+			return 3;
+	}
+
+	/* check for the fLaC signature */
+	if(0 == memcmp(FLAC__STREAM_SYNC_STRING, buffer, FLAC__STREAM_SYNC_LENGTH))
+		return 0;
+	else
+		return 3;
+}
+
+unsigned seek_to_first_metadata_block_(FILE *f)
+{
+	return seek_to_first_metadata_block_cb_((FLAC__IOHandle)f, (FLAC__IOCallback_Read)fread, fseek_wrapper_);
+}
+
+FLAC__bool simple_iterator_copy_file_prefix_(FLAC__Metadata_SimpleIterator *iterator, FILE **tempfile, char **tempfilename, FLAC__bool append)
+{
+	const long offset_end = append? iterator->offset[iterator->depth] + (long)FLAC__STREAM_METADATA_HEADER_LENGTH + (long)iterator->length : iterator->offset[iterator->depth];
+
+	if(0 != fseek(iterator->file, 0, SEEK_SET)) {
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+		return false;
+	}
+	if(!open_tempfile_(iterator->filename, iterator->tempfile_path_prefix, tempfile, tempfilename, &iterator->status)) {
+		cleanup_tempfile_(tempfile, tempfilename);
+		return false;
+	}
+	if(!copy_n_bytes_from_file_(iterator->file, *tempfile, offset_end, &iterator->status)) {
+		cleanup_tempfile_(tempfile, tempfilename);
+		return false;
+	}
+
+	return true;
+}
+
+FLAC__bool simple_iterator_copy_file_postfix_(FLAC__Metadata_SimpleIterator *iterator, FILE **tempfile, char **tempfilename, int fixup_is_last_code, long fixup_is_last_flag_offset, FLAC__bool backup)
+{
+	long save_offset = iterator->offset[iterator->depth]; /*@@@ 2G limit */
+	FLAC__ASSERT(0 != *tempfile);
+
+	if(0 != fseek(iterator->file, save_offset + FLAC__STREAM_METADATA_HEADER_LENGTH + iterator->length, SEEK_SET)) {
+		cleanup_tempfile_(tempfile, tempfilename);
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+		return false;
+	}
+	if(!copy_remaining_bytes_from_file_(iterator->file, *tempfile, &iterator->status)) {
+		cleanup_tempfile_(tempfile, tempfilename);
+		return false;
+	}
+
+	if(fixup_is_last_code != 0) {
+		/*
+		 * if code == 1, it means a block was appended to the end so
+		 *   we have to clear the is_last flag of the previous block
+		 * if code == -1, it means the last block was deleted so
+		 *   we have to set the is_last flag of the previous block
+		 */
+		/* MAGIC NUMBERs here; we know the is_last flag is the high bit of the byte at this location */
+		FLAC__byte x;
+		if(0 != fseek(*tempfile, fixup_is_last_flag_offset, SEEK_SET)) {
+			cleanup_tempfile_(tempfile, tempfilename);
+			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+			return false;
+		}
+		if(fread(&x, 1, 1, *tempfile) != 1) {
+			cleanup_tempfile_(tempfile, tempfilename);
+			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+			return false;
+		}
+		if(fixup_is_last_code > 0) {
+			FLAC__ASSERT(x & 0x80);
+			x &= 0x7f;
+		}
+		else {
+			FLAC__ASSERT(!(x & 0x80));
+			x |= 0x80;
+		}
+		if(0 != fseek(*tempfile, fixup_is_last_flag_offset, SEEK_SET)) {
+			cleanup_tempfile_(tempfile, tempfilename);
+			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+			return false;
+		}
+		if(local__fwrite(&x, 1, 1, *tempfile) != 1) {
+			cleanup_tempfile_(tempfile, tempfilename);
+			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+			return false;
+		}
+	}
+
+	(void)fclose(iterator->file);
+
+	if(!transport_tempfile_(iterator->filename, tempfile, tempfilename, &iterator->status))
+		return false;
+
+	if(iterator->has_stats)
+		set_file_stats_(iterator->filename, &iterator->stats);
+
+	if(!simple_iterator_prime_input_(iterator, !iterator->is_writable))
+		return false;
+	if(backup) {
+		while(iterator->offset[iterator->depth] + (long)FLAC__STREAM_METADATA_HEADER_LENGTH + (long)iterator->length < save_offset)
+			if(!FLAC__metadata_simple_iterator_next(iterator))
+				return false;
+		return true;
+	}
+	else {
+		/* move the iterator to it's original block faster by faking a push, then doing a pop_ */
+		FLAC__ASSERT(iterator->depth == 0);
+		iterator->offset[0] = save_offset;
+		iterator->depth++;
+		return simple_iterator_pop_(iterator);
+	}
+}
+
+FLAC__bool copy_n_bytes_from_file_(FILE *file, FILE *tempfile, unsigned bytes/*@@@ 4G limit*/, FLAC__Metadata_SimpleIteratorStatus *status)
+{
+	FLAC__byte buffer[8192];
+	unsigned n;
+
+	while(bytes > 0) {
+		n = min(sizeof(buffer), bytes);
+		if(fread(buffer, 1, n, file) != n) {
+			*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+			return false;
+		}
+		if(local__fwrite(buffer, 1, n, tempfile) != n) {
+			*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+			return false;
+		}
+		bytes -= n;
+	}
+
+	return true;
+}
+
+FLAC__bool copy_n_bytes_from_file_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write_cb, unsigned bytes/*@@@ 4G limit*/, FLAC__Metadata_SimpleIteratorStatus *status)
+{
+	FLAC__byte buffer[8192];
+	unsigned n;
+
+	while(bytes > 0) {
+		n = min(sizeof(buffer), bytes);
+		if(read_cb(buffer, 1, n, handle) != n) {
+			*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+			return false;
+		}
+		if(temp_write_cb(buffer, 1, n, temp_handle) != n) {
+			*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+			return false;
+		}
+		bytes -= n;
+	}
+
+	return true;
+}
+
+FLAC__bool copy_remaining_bytes_from_file_(FILE *file, FILE *tempfile, FLAC__Metadata_SimpleIteratorStatus *status)
+{
+	FLAC__byte buffer[8192];
+	size_t n;
+
+	while(!feof(file)) {
+		n = fread(buffer, 1, sizeof(buffer), file);
+		if(n == 0 && !feof(file)) {
+			*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+			return false;
+		}
+		if(n > 0 && local__fwrite(buffer, 1, n, tempfile) != n) {
+			*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+			return false;
+		}
+	}
+
+	return true;
+}
+
+FLAC__bool copy_remaining_bytes_from_file_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Eof eof_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write_cb, FLAC__Metadata_SimpleIteratorStatus *status)
+{
+	FLAC__byte buffer[8192];
+	size_t n;
+
+	while(!eof_cb(handle)) {
+		n = read_cb(buffer, 1, sizeof(buffer), handle);
+		if(n == 0 && !eof_cb(handle)) {
+			*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+			return false;
+		}
+		if(n > 0 && temp_write_cb(buffer, 1, n, temp_handle) != n) {
+			*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+			return false;
+		}
+	}
+
+	return true;
+}
+
+FLAC__bool open_tempfile_(const char *filename, const char *tempfile_path_prefix, FILE **tempfile, char **tempfilename, FLAC__Metadata_SimpleIteratorStatus *status)
+{
+	static const char *tempfile_suffix = ".metadata_edit";
+	if(0 == tempfile_path_prefix) {
+		if(0 == (*tempfilename = (char*)malloc(strlen(filename) + strlen(tempfile_suffix) + 1))) {
+			*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+			return false;
+		}
+		strcpy(*tempfilename, filename);
+		strcat(*tempfilename, tempfile_suffix);
+	}
+	else {
+		const char *p = strrchr(filename, '/');
+		if(0 == p)
+			p = filename;
+		else
+			p++;
+
+		if(0 == (*tempfilename = (char*)malloc(strlen(tempfile_path_prefix) + 1 + strlen(p) + strlen(tempfile_suffix) + 1))) {
+			*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+			return false;
+		}
+		strcpy(*tempfilename, tempfile_path_prefix);
+		strcat(*tempfilename, "/");
+		strcat(*tempfilename, p);
+		strcat(*tempfilename, tempfile_suffix);
+	}
+
+	if(0 == (*tempfile = fopen(*tempfilename, "w+b"))) {
+		*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE;
+		return false;
+	}
+
+	return true;
+}
+
+FLAC__bool transport_tempfile_(const char *filename, FILE **tempfile, char **tempfilename, FLAC__Metadata_SimpleIteratorStatus *status)
+{
+	FLAC__ASSERT(0 != filename);
+	FLAC__ASSERT(0 != tempfile);
+	FLAC__ASSERT(0 != *tempfile);
+	FLAC__ASSERT(0 != tempfilename);
+	FLAC__ASSERT(0 != *tempfilename);
+	FLAC__ASSERT(0 != status);
+
+	(void)fclose(*tempfile);
+	*tempfile = 0;
+
+#if defined _MSC_VER || defined __MINGW32__
+	if(unlink(filename) < 0) {
+		cleanup_tempfile_(tempfile, tempfilename);
+		*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_UNLINK_ERROR;
+		return false;
+	}
+#endif
+
+	/*@@@ to fully support the tempfile_path_prefix we need to update this piece to actually copy across filesystems instead of just rename(): */
+	if(0 != rename(*tempfilename, filename)) {
+		cleanup_tempfile_(tempfile, tempfilename);
+		*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_RENAME_ERROR;
+		return false;
+	}
+
+	cleanup_tempfile_(tempfile, tempfilename);
+
+	return true;
+}
+
+void cleanup_tempfile_(FILE **tempfile, char **tempfilename)
+{
+	if(0 != *tempfile) {
+		(void)fclose(*tempfile);
+		*tempfile = 0;
+	}
+
+	if(0 != *tempfilename) {
+		(void)unlink(*tempfilename);
+		free(*tempfilename);
+		*tempfilename = 0;
+	}
+}
+
+FLAC__bool get_file_stats_(const char *filename, struct stat *stats)
+{
+	FLAC__ASSERT(0 != filename);
+	FLAC__ASSERT(0 != stats);
+	return (0 == stat(filename, stats));
+}
+
+void set_file_stats_(const char *filename, struct stat *stats)
+{
+	struct utimbuf srctime;
+
+	FLAC__ASSERT(0 != filename);
+	FLAC__ASSERT(0 != stats);
+
+	srctime.actime = stats->st_atime;
+	srctime.modtime = stats->st_mtime;
+	(void)chmod(filename, stats->st_mode);
+	(void)utime(filename, &srctime);
+#if !defined _MSC_VER && !defined __MINGW32__
+	(void)chown(filename, stats->st_uid, -1);
+	(void)chown(filename, -1, stats->st_gid);
+#endif
+}
+
+/* @@@ WATCHOUT @@@
+ * We cast FLAC__int64 to long and use fseek()/ftell() because
+ * none of our operations on metadata is ever likely to go past
+ * 2 gigabytes.
+ */
+int fseek_wrapper_(FLAC__IOHandle handle, FLAC__int64 offset, int whence)
+{
+	FLAC__ASSERT(offset <= 0x7fffffff);
+	return fseek((FILE*)handle, (long)offset, whence);
+}
+
+FLAC__int64 ftell_wrapper_(FLAC__IOHandle handle)
+{
+	return (long)ftell((FILE*)handle);
+}
+
+FLAC__Metadata_ChainStatus get_equivalent_status_(FLAC__Metadata_SimpleIteratorStatus status)
+{
+	switch(status) {
+		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK:
+			return FLAC__METADATA_CHAIN_STATUS_OK;
+		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT:
+			return FLAC__METADATA_CHAIN_STATUS_ILLEGAL_INPUT;
+		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE:
+			return FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE;
+		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE:
+			return FLAC__METADATA_CHAIN_STATUS_NOT_A_FLAC_FILE;
+		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE:
+			return FLAC__METADATA_CHAIN_STATUS_NOT_WRITABLE;
+		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA:
+			return FLAC__METADATA_CHAIN_STATUS_BAD_METADATA;
+		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR:
+			return FLAC__METADATA_CHAIN_STATUS_READ_ERROR;
+		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR:
+			return FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
+		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR:
+			return FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR;
+		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_RENAME_ERROR:
+			return FLAC__METADATA_CHAIN_STATUS_RENAME_ERROR;
+		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_UNLINK_ERROR:
+			return FLAC__METADATA_CHAIN_STATUS_UNLINK_ERROR;
+		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR:
+			return FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
+		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_INTERNAL_ERROR:
+		default:
+			return FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR;
+	}
+}
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/metadata_object.c
@@ -1,0 +1,1321 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001,2002,2003,2004  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "private/metadata.h"
+
+#include "FLAC/assert.h"
+
+
+/****************************************************************************
+ *
+ * Local routines
+ *
+ ***************************************************************************/
+
+static FLAC__bool copy_bytes_(FLAC__byte **to, const FLAC__byte *from, unsigned bytes)
+{
+	if(bytes > 0 && 0 != from) {
+		FLAC__byte *x;
+		if(0 == (x = (FLAC__byte*)malloc(bytes)))
+			return false;
+		memcpy(x, from, bytes);
+		*to = x;
+	}
+	else {
+		FLAC__ASSERT(0 == from);
+		FLAC__ASSERT(bytes == 0);
+		*to = 0;
+	}
+	return true;
+}
+
+static FLAC__bool copy_vcentry_(FLAC__StreamMetadata_VorbisComment_Entry *to, const FLAC__StreamMetadata_VorbisComment_Entry *from)
+{
+	to->length = from->length;
+	if(0 == from->entry) {
+		FLAC__ASSERT(from->length == 0);
+		to->entry = 0;
+	}
+	else {
+		FLAC__byte *x;
+		FLAC__ASSERT(from->length > 0);
+		if(0 == (x = (FLAC__byte*)malloc(from->length)))
+			return false;
+		memcpy(x, from->entry, from->length);
+		to->entry = x;
+	}
+	return true;
+}
+
+static FLAC__bool copy_track_(FLAC__StreamMetadata_CueSheet_Track *to, const FLAC__StreamMetadata_CueSheet_Track *from)
+{
+	memcpy(to, from, sizeof(FLAC__StreamMetadata_CueSheet_Track));
+	if(0 == from->indices) {
+		FLAC__ASSERT(from->num_indices == 0);
+	}
+	else {
+		FLAC__StreamMetadata_CueSheet_Index *x;
+		FLAC__ASSERT(from->num_indices > 0);
+		if(0 == (x = (FLAC__StreamMetadata_CueSheet_Index*)malloc(from->num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index))))
+			return false;
+		memcpy(x, from->indices, from->num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index));
+		to->indices = x;
+	}
+	return true;
+}
+
+static void seektable_calculate_length_(FLAC__StreamMetadata *object)
+{
+	FLAC__ASSERT(0 != object);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
+
+	object->length = object->data.seek_table.num_points * FLAC__STREAM_METADATA_SEEKPOINT_LENGTH;
+}
+
+static FLAC__StreamMetadata_SeekPoint *seekpoint_array_new_(unsigned num_points)
+{
+	FLAC__StreamMetadata_SeekPoint *object_array;
+
+	FLAC__ASSERT(num_points > 0);
+
+	object_array = (FLAC__StreamMetadata_SeekPoint*)malloc(num_points * sizeof(FLAC__StreamMetadata_SeekPoint));
+
+	if(0 != object_array) {
+		unsigned i;
+		for(i = 0; i < num_points; i++) {
+			object_array[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
+			object_array[i].stream_offset = 0;
+			object_array[i].frame_samples = 0;
+		}
+	}
+
+	return object_array;
+}
+
+static void vorbiscomment_calculate_length_(FLAC__StreamMetadata *object)
+{
+	unsigned i;
+
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+	object->length = (FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN) / 8;
+	object->length += object->data.vorbis_comment.vendor_string.length;
+	object->length += (FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN) / 8;
+	for(i = 0; i < object->data.vorbis_comment.num_comments; i++) {
+		object->length += (FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8);
+		object->length += object->data.vorbis_comment.comments[i].length;
+	}
+}
+
+static FLAC__StreamMetadata_VorbisComment_Entry *vorbiscomment_entry_array_new_(unsigned num_comments)
+{
+	FLAC__ASSERT(num_comments > 0);
+
+	return (FLAC__StreamMetadata_VorbisComment_Entry*)calloc(num_comments, sizeof(FLAC__StreamMetadata_VorbisComment_Entry));
+}
+
+static void vorbiscomment_entry_array_delete_(FLAC__StreamMetadata_VorbisComment_Entry *object_array, unsigned num_comments)
+{
+	unsigned i;
+
+	FLAC__ASSERT(0 != object_array && num_comments > 0);
+
+	for(i = 0; i < num_comments; i++)
+		if(0 != object_array[i].entry)
+			free(object_array[i].entry);
+
+	if(0 != object_array)
+		free(object_array);
+}
+
+static FLAC__StreamMetadata_VorbisComment_Entry *vorbiscomment_entry_array_copy_(const FLAC__StreamMetadata_VorbisComment_Entry *object_array, unsigned num_comments)
+{
+	FLAC__StreamMetadata_VorbisComment_Entry *return_array;
+
+	FLAC__ASSERT(0 != object_array);
+	FLAC__ASSERT(num_comments > 0);
+
+	return_array = vorbiscomment_entry_array_new_(num_comments);
+
+	if(0 != return_array) {
+		unsigned i;
+
+		for(i = 0; i < num_comments; i++) {
+			if(!copy_vcentry_(return_array+i, object_array+i)) {
+				vorbiscomment_entry_array_delete_(return_array, num_comments);
+				return 0;
+			}
+		}
+	}
+
+	return return_array;
+}
+
+static FLAC__bool vorbiscomment_set_entry_(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry *dest, const FLAC__StreamMetadata_VorbisComment_Entry *src, FLAC__bool copy)
+{
+	FLAC__byte *save;
+
+	FLAC__ASSERT(0 != object);
+	FLAC__ASSERT(0 != dest);
+	FLAC__ASSERT(0 != src);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+	FLAC__ASSERT((0 != src->entry && src->length > 0) || (0 == src->entry && src->length == 0));
+
+	save = dest->entry;
+
+	/* do the copy first so that if we fail we leave the object untouched */
+	if(copy && (0 != src->entry && src->length > 0)) {
+		if(!copy_vcentry_(dest, src))
+			return false;
+	}
+	else {
+		/* either we're not copying or the src is null */
+		*dest = *src;
+	}
+
+	if(0 != save)
+		free(save);
+
+	vorbiscomment_calculate_length_(object);
+	return true;
+}
+
+static void cuesheet_calculate_length_(FLAC__StreamMetadata *object)
+{
+	unsigned i;
+
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
+
+	object->length = (
+		FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN
+	) / 8;
+
+	object->length += object->data.cue_sheet.num_tracks * (
+		FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN
+	) / 8;
+
+	for(i = 0; i < object->data.cue_sheet.num_tracks; i++) {
+		object->length += object->data.cue_sheet.tracks[i].num_indices * (
+			FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN +
+			FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN +
+			FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN
+		) / 8;
+	}
+}
+
+static FLAC__StreamMetadata_CueSheet_Index *cuesheet_track_index_array_new_(unsigned num_indices)
+{
+	FLAC__ASSERT(num_indices > 0);
+
+	return (FLAC__StreamMetadata_CueSheet_Index*)calloc(num_indices, sizeof(FLAC__StreamMetadata_CueSheet_Index));
+}
+
+static FLAC__StreamMetadata_CueSheet_Track *cuesheet_track_array_new_(unsigned num_tracks)
+{
+	FLAC__ASSERT(num_tracks > 0);
+
+	return (FLAC__StreamMetadata_CueSheet_Track*)calloc(num_tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track));
+}
+
+static void cuesheet_track_array_delete_(FLAC__StreamMetadata_CueSheet_Track *object_array, unsigned num_tracks)
+{
+	unsigned i;
+
+	FLAC__ASSERT(0 != object_array && num_tracks > 0);
+
+	for(i = 0; i < num_tracks; i++) {
+		if(0 != object_array[i].indices) {
+			FLAC__ASSERT(object_array[i].num_indices > 0);
+			free(object_array[i].indices);
+		}
+	}
+
+	if(0 != object_array)
+		free(object_array);
+}
+
+static FLAC__StreamMetadata_CueSheet_Track *cuesheet_track_array_copy_(const FLAC__StreamMetadata_CueSheet_Track *object_array, unsigned num_tracks)
+{
+	FLAC__StreamMetadata_CueSheet_Track *return_array;
+
+	FLAC__ASSERT(0 != object_array);
+	FLAC__ASSERT(num_tracks > 0);
+
+	return_array = cuesheet_track_array_new_(num_tracks);
+
+	if(0 != return_array) {
+		unsigned i;
+
+		for(i = 0; i < num_tracks; i++) {
+			if(!copy_track_(return_array+i, object_array+i)) {
+				cuesheet_track_array_delete_(return_array, num_tracks);
+				return 0;
+			}
+		}
+	}
+
+	return return_array;
+}
+
+static FLAC__bool cuesheet_set_track_(FLAC__StreamMetadata *object, FLAC__StreamMetadata_CueSheet_Track *dest, const FLAC__StreamMetadata_CueSheet_Track *src, FLAC__bool copy)
+{
+	FLAC__StreamMetadata_CueSheet_Index *save;
+
+	FLAC__ASSERT(0 != object);
+	FLAC__ASSERT(0 != dest);
+	FLAC__ASSERT(0 != src);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
+	FLAC__ASSERT((0 != src->indices && src->num_indices > 0) || (0 == src->indices && src->num_indices == 0));
+
+	save = dest->indices;
+
+	/* do the copy first so that if we fail we leave the object untouched */
+	if(copy) {
+		if(!copy_track_(dest, src))
+			return false;
+	}
+	else {
+		*dest = *src;
+	}
+
+	if(0 != save)
+		free(save);
+
+	cuesheet_calculate_length_(object);
+	return true;
+}
+
+
+/****************************************************************************
+ *
+ * Metadata object routines
+ *
+ ***************************************************************************/
+
+FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_new(FLAC__MetadataType type)
+{
+	FLAC__StreamMetadata *object;
+
+	if(type > FLAC__MAX_METADATA_TYPE_CODE)
+		return 0;
+
+	object = (FLAC__StreamMetadata*)calloc(1, sizeof(FLAC__StreamMetadata));
+	if(0 != object) {
+		object->is_last = false;
+		object->type = type;
+		switch(type) {
+			case FLAC__METADATA_TYPE_STREAMINFO:
+				object->length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH;
+				break;
+			case FLAC__METADATA_TYPE_PADDING:
+				/* calloc() took care of this for us:
+				object->length = 0;
+				*/
+				break;
+			case FLAC__METADATA_TYPE_APPLICATION:
+				object->length = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8;
+				/* calloc() took care of this for us:
+				object->data.application.data = 0;
+				*/
+				break;
+			case FLAC__METADATA_TYPE_SEEKTABLE:
+				/* calloc() took care of this for us:
+				object->length = 0;
+				object->data.seek_table.num_points = 0;
+				object->data.seek_table.points = 0;
+				*/
+				break;
+			case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+				{
+					object->data.vorbis_comment.vendor_string.length = (unsigned)strlen(FLAC__VENDOR_STRING);
+					if(!copy_bytes_(&object->data.vorbis_comment.vendor_string.entry, (const FLAC__byte*)FLAC__VENDOR_STRING, object->data.vorbis_comment.vendor_string.length)) {
+						free(object);
+						return 0;
+					}
+					vorbiscomment_calculate_length_(object);
+				}
+				break;
+			case FLAC__METADATA_TYPE_CUESHEET:
+				cuesheet_calculate_length_(object);
+				break;
+			default:
+				/* calloc() took care of this for us:
+				object->length = 0;
+				object->data.unknown.data = 0;
+				*/
+				break;
+		}
+	}
+
+	return object;
+}
+
+FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_clone(const FLAC__StreamMetadata *object)
+{
+	FLAC__StreamMetadata *to;
+
+	FLAC__ASSERT(0 != object);
+
+	if(0 != (to = FLAC__metadata_object_new(object->type))) {
+		to->is_last = object->is_last;
+		to->type = object->type;
+		to->length = object->length;
+		switch(to->type) {
+			case FLAC__METADATA_TYPE_STREAMINFO:
+				memcpy(&to->data.stream_info, &object->data.stream_info, sizeof(FLAC__StreamMetadata_StreamInfo));
+				break;
+			case FLAC__METADATA_TYPE_PADDING:
+				break;
+			case FLAC__METADATA_TYPE_APPLICATION:
+				memcpy(&to->data.application.id, &object->data.application.id, FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8);
+				if(!copy_bytes_(&to->data.application.data, object->data.application.data, object->length - FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8)) {
+					FLAC__metadata_object_delete(to);
+					return 0;
+				}
+				break;
+			case FLAC__METADATA_TYPE_SEEKTABLE:
+				to->data.seek_table.num_points = object->data.seek_table.num_points;
+				if(!copy_bytes_((FLAC__byte**)&to->data.seek_table.points, (FLAC__byte*)object->data.seek_table.points, object->data.seek_table.num_points * sizeof(FLAC__StreamMetadata_SeekPoint))) {
+					FLAC__metadata_object_delete(to);
+					return 0;
+				}
+				break;
+			case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+				if(0 != to->data.vorbis_comment.vendor_string.entry) {
+					free(to->data.vorbis_comment.vendor_string.entry);
+					to->data.vorbis_comment.vendor_string.entry = 0;
+				}
+				if(!copy_vcentry_(&to->data.vorbis_comment.vendor_string, &object->data.vorbis_comment.vendor_string)) {
+					FLAC__metadata_object_delete(to);
+					return 0;
+				}
+				if(object->data.vorbis_comment.num_comments == 0) {
+					FLAC__ASSERT(0 == object->data.vorbis_comment.comments);
+					to->data.vorbis_comment.comments = 0;
+				}
+				else {
+					FLAC__ASSERT(0 != object->data.vorbis_comment.comments);
+					to->data.vorbis_comment.comments = vorbiscomment_entry_array_copy_(object->data.vorbis_comment.comments, object->data.vorbis_comment.num_comments);
+					if(0 == to->data.vorbis_comment.comments) {
+						FLAC__metadata_object_delete(to);
+						return 0;
+					}
+				}
+				to->data.vorbis_comment.num_comments = object->data.vorbis_comment.num_comments;
+				break;
+			case FLAC__METADATA_TYPE_CUESHEET:
+				memcpy(&to->data.cue_sheet, &object->data.cue_sheet, sizeof(FLAC__StreamMetadata_CueSheet));
+				if(object->data.cue_sheet.num_tracks == 0) {
+					FLAC__ASSERT(0 == object->data.cue_sheet.tracks);
+				}
+				else {
+					FLAC__ASSERT(0 != object->data.cue_sheet.tracks);
+					to->data.cue_sheet.tracks = cuesheet_track_array_copy_(object->data.cue_sheet.tracks, object->data.cue_sheet.num_tracks);
+					if(0 == to->data.cue_sheet.tracks) {
+						FLAC__metadata_object_delete(to);
+						return 0;
+					}
+				}
+				break;
+			default:
+				if(!copy_bytes_(&to->data.unknown.data, object->data.unknown.data, object->length)) {
+					FLAC__metadata_object_delete(to);
+					return 0;
+				}
+				break;
+		}
+	}
+
+	return to;
+}
+
+void FLAC__metadata_object_delete_data(FLAC__StreamMetadata *object)
+{
+	FLAC__ASSERT(0 != object);
+
+	switch(object->type) {
+		case FLAC__METADATA_TYPE_STREAMINFO:
+		case FLAC__METADATA_TYPE_PADDING:
+			break;
+		case FLAC__METADATA_TYPE_APPLICATION:
+			if(0 != object->data.application.data) {
+				free(object->data.application.data);
+				object->data.application.data = 0;
+			}
+			break;
+		case FLAC__METADATA_TYPE_SEEKTABLE:
+			if(0 != object->data.seek_table.points) {
+				free(object->data.seek_table.points);
+				object->data.seek_table.points = 0;
+			}
+			break;
+		case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+			if(0 != object->data.vorbis_comment.vendor_string.entry) {
+				free(object->data.vorbis_comment.vendor_string.entry);
+				object->data.vorbis_comment.vendor_string.entry = 0;
+			}
+			if(0 != object->data.vorbis_comment.comments) {
+				FLAC__ASSERT(object->data.vorbis_comment.num_comments > 0);
+				vorbiscomment_entry_array_delete_(object->data.vorbis_comment.comments, object->data.vorbis_comment.num_comments);
+			}
+			break;
+		case FLAC__METADATA_TYPE_CUESHEET:
+			if(0 != object->data.cue_sheet.tracks) {
+				FLAC__ASSERT(object->data.cue_sheet.num_tracks > 0);
+				cuesheet_track_array_delete_(object->data.cue_sheet.tracks, object->data.cue_sheet.num_tracks);
+			}
+			break;
+		default:
+			if(0 != object->data.unknown.data) {
+				free(object->data.unknown.data);
+				object->data.unknown.data = 0;
+			}
+			break;
+	}
+}
+
+FLAC_API void FLAC__metadata_object_delete(FLAC__StreamMetadata *object)
+{
+	FLAC__metadata_object_delete_data(object);
+	free(object);
+}
+
+static FLAC__bool compare_block_data_streaminfo_(const FLAC__StreamMetadata_StreamInfo *block1, const FLAC__StreamMetadata_StreamInfo *block2)
+{
+	if(block1->min_blocksize != block2->min_blocksize)
+		return false;
+	if(block1->max_blocksize != block2->max_blocksize)
+		return false;
+	if(block1->min_framesize != block2->min_framesize)
+		return false;
+	if(block1->max_framesize != block2->max_framesize)
+		return false;
+	if(block1->sample_rate != block2->sample_rate)
+		return false;
+	if(block1->channels != block2->channels)
+		return false;
+	if(block1->bits_per_sample != block2->bits_per_sample)
+		return false;
+	if(block1->total_samples != block2->total_samples)
+		return false;
+	if(0 != memcmp(block1->md5sum, block2->md5sum, 16))
+		return false;
+	return true;
+}
+
+static FLAC__bool compare_block_data_application_(const FLAC__StreamMetadata_Application *block1, const FLAC__StreamMetadata_Application *block2, unsigned block_length)
+{
+	FLAC__ASSERT(0 != block1);
+	FLAC__ASSERT(0 != block2);
+	FLAC__ASSERT(block_length >= sizeof(block1->id));
+
+	if(0 != memcmp(block1->id, block2->id, sizeof(block1->id)))
+		return false;
+	if(0 != block1->data && 0 != block2->data)
+		return 0 == memcmp(block1->data, block2->data, block_length - sizeof(block1->id));
+	else
+		return block1->data == block2->data;
+}
+
+static FLAC__bool compare_block_data_seektable_(const FLAC__StreamMetadata_SeekTable *block1, const FLAC__StreamMetadata_SeekTable *block2)
+{
+	unsigned i;
+
+	FLAC__ASSERT(0 != block1);
+	FLAC__ASSERT(0 != block2);
+
+	if(block1->num_points != block2->num_points)
+		return false;
+
+	if(0 != block1->points && 0 != block2->points) {
+		for(i = 0; i < block1->num_points; i++) {
+			if(block1->points[i].sample_number != block2->points[i].sample_number)
+				return false;
+			if(block1->points[i].stream_offset != block2->points[i].stream_offset)
+				return false;
+			if(block1->points[i].frame_samples != block2->points[i].frame_samples)
+				return false;
+		}
+		return true;
+	}
+	else
+		return block1->points == block2->points;
+}
+
+static FLAC__bool compare_block_data_vorbiscomment_(const FLAC__StreamMetadata_VorbisComment *block1, const FLAC__StreamMetadata_VorbisComment *block2)
+{
+	unsigned i;
+
+	if(block1->vendor_string.length != block2->vendor_string.length)
+		return false;
+
+	if(0 != block1->vendor_string.entry && 0 != block2->vendor_string.entry) {
+		if(0 != memcmp(block1->vendor_string.entry, block2->vendor_string.entry, block1->vendor_string.length))
+			return false;
+	}
+	else if(block1->vendor_string.entry != block2->vendor_string.entry)
+		return false;
+
+	if(block1->num_comments != block2->num_comments)
+		return false;
+
+	for(i = 0; i < block1->num_comments; i++) {
+		if(0 != block1->comments[i].entry && 0 != block2->comments[i].entry) {
+			if(0 != memcmp(block1->comments[i].entry, block2->comments[i].entry, block1->comments[i].length))
+				return false;
+		}
+		else if(block1->comments[i].entry != block2->comments[i].entry)
+			return false;
+	}
+	return true;
+}
+
+static FLAC__bool compare_block_data_cuesheet_(const FLAC__StreamMetadata_CueSheet *block1, const FLAC__StreamMetadata_CueSheet *block2)
+{
+	unsigned i, j;
+
+	if(0 != strcmp(block1->media_catalog_number, block2->media_catalog_number))
+		return false;
+
+	if(block1->lead_in != block2->lead_in)
+		return false;
+
+	if(block1->is_cd != block2->is_cd)
+		return false;
+
+	if(block1->num_tracks != block2->num_tracks)
+		return false;
+
+	if(0 != block1->tracks && 0 != block2->tracks) {
+		FLAC__ASSERT(block1->num_tracks > 0);
+		for(i = 0; i < block1->num_tracks; i++) {
+			if(block1->tracks[i].offset != block2->tracks[i].offset)
+				return false;
+			if(block1->tracks[i].number != block2->tracks[i].number)
+				return false;
+			if(0 != memcmp(block1->tracks[i].isrc, block2->tracks[i].isrc, sizeof(block1->tracks[i].isrc)))
+				return false;
+			if(block1->tracks[i].type != block2->tracks[i].type)
+				return false;
+			if(block1->tracks[i].pre_emphasis != block2->tracks[i].pre_emphasis)
+				return false;
+			if(block1->tracks[i].num_indices != block2->tracks[i].num_indices)
+				return false;
+			if(0 != block1->tracks[i].indices && 0 != block2->tracks[i].indices) {
+				FLAC__ASSERT(block1->tracks[i].num_indices > 0);
+				for(j = 0; j < block1->tracks[i].num_indices; j++) {
+					if(block1->tracks[i].indices[j].offset != block2->tracks[i].indices[j].offset)
+						return false;
+					if(block1->tracks[i].indices[j].number != block2->tracks[i].indices[j].number)
+						return false;
+				}
+			}
+			else if(block1->tracks[i].indices != block2->tracks[i].indices)
+				return false;
+		}
+	}
+	else if(block1->tracks != block2->tracks)
+		return false;
+	return true;
+}
+
+static FLAC__bool compare_block_data_unknown_(const FLAC__StreamMetadata_Unknown *block1, const FLAC__StreamMetadata_Unknown *block2, unsigned block_length)
+{
+	FLAC__ASSERT(0 != block1);
+	FLAC__ASSERT(0 != block2);
+
+	if(0 != block1->data && 0 != block2->data)
+		return 0 == memcmp(block1->data, block2->data, block_length);
+	else
+		return block1->data == block2->data;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_is_equal(const FLAC__StreamMetadata *block1, const FLAC__StreamMetadata *block2)
+{
+	FLAC__ASSERT(0 != block1);
+	FLAC__ASSERT(0 != block2);
+
+	if(block1->type != block2->type) {
+		return false;
+	}
+	if(block1->is_last != block2->is_last) {
+		return false;
+	}
+	if(block1->length != block2->length) {
+		return false;
+	}
+	switch(block1->type) {
+		case FLAC__METADATA_TYPE_STREAMINFO:
+			return compare_block_data_streaminfo_(&block1->data.stream_info, &block2->data.stream_info);
+		case FLAC__METADATA_TYPE_PADDING:
+			return true; /* we don't compare the padding guts */
+		case FLAC__METADATA_TYPE_APPLICATION:
+			return compare_block_data_application_(&block1->data.application, &block2->data.application, block1->length);
+		case FLAC__METADATA_TYPE_SEEKTABLE:
+			return compare_block_data_seektable_(&block1->data.seek_table, &block2->data.seek_table);
+		case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+			return compare_block_data_vorbiscomment_(&block1->data.vorbis_comment, &block2->data.vorbis_comment);
+		case FLAC__METADATA_TYPE_CUESHEET:
+			return compare_block_data_cuesheet_(&block1->data.cue_sheet, &block2->data.cue_sheet);
+		default:
+			return compare_block_data_unknown_(&block1->data.unknown, &block2->data.unknown, block1->length);
+	}
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_application_set_data(FLAC__StreamMetadata *object, FLAC__byte *data, unsigned length, FLAC__bool copy)
+{
+	FLAC__byte *save;
+
+	FLAC__ASSERT(0 != object);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_APPLICATION);
+	FLAC__ASSERT((0 != data && length > 0) || (0 == data && length == 0 && copy == false));
+
+	save = object->data.application.data;
+
+	/* do the copy first so that if we fail we leave the object untouched */
+	if(copy) {
+		if(!copy_bytes_(&object->data.application.data, data, length))
+			return false;
+	}
+	else {
+		object->data.application.data = data;
+	}
+
+	if(0 != save)
+		free(save);
+
+	object->length = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8 + length;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_resize_points(FLAC__StreamMetadata *object, unsigned new_num_points)
+{
+	FLAC__ASSERT(0 != object);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
+
+	if(0 == object->data.seek_table.points) {
+		FLAC__ASSERT(object->data.seek_table.num_points == 0);
+		if(0 == new_num_points)
+			return true;
+		else if(0 == (object->data.seek_table.points = seekpoint_array_new_(new_num_points)))
+			return false;
+	}
+	else {
+		const unsigned old_size = object->data.seek_table.num_points * sizeof(FLAC__StreamMetadata_SeekPoint);
+		const unsigned new_size = new_num_points * sizeof(FLAC__StreamMetadata_SeekPoint);
+
+		FLAC__ASSERT(object->data.seek_table.num_points > 0);
+
+		if(new_size == 0) {
+			free(object->data.seek_table.points);
+			object->data.seek_table.points = 0;
+		}
+		else if(0 == (object->data.seek_table.points = (FLAC__StreamMetadata_SeekPoint*)realloc(object->data.seek_table.points, new_size)))
+			return false;
+
+		/* if growing, set new elements to placeholders */
+		if(new_size > old_size) {
+			unsigned i;
+			for(i = object->data.seek_table.num_points; i < new_num_points; i++) {
+				object->data.seek_table.points[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
+				object->data.seek_table.points[i].stream_offset = 0;
+				object->data.seek_table.points[i].frame_samples = 0;
+			}
+		}
+	}
+
+	object->data.seek_table.num_points = new_num_points;
+
+	seektable_calculate_length_(object);
+	return true;
+}
+
+FLAC_API void FLAC__metadata_object_seektable_set_point(FLAC__StreamMetadata *object, unsigned point_num, FLAC__StreamMetadata_SeekPoint point)
+{
+	FLAC__ASSERT(0 != object);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
+	FLAC__ASSERT(point_num < object->data.seek_table.num_points);
+
+	object->data.seek_table.points[point_num] = point;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_insert_point(FLAC__StreamMetadata *object, unsigned point_num, FLAC__StreamMetadata_SeekPoint point)
+{
+	int i;
+
+	FLAC__ASSERT(0 != object);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
+	FLAC__ASSERT(point_num <= object->data.seek_table.num_points);
+
+	if(!FLAC__metadata_object_seektable_resize_points(object, object->data.seek_table.num_points+1))
+		return false;
+
+	/* move all points >= point_num forward one space */
+	for(i = (int)object->data.seek_table.num_points-1; i > (int)point_num; i--)
+		object->data.seek_table.points[i] = object->data.seek_table.points[i-1];
+
+	FLAC__metadata_object_seektable_set_point(object, point_num, point);
+	seektable_calculate_length_(object);
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_delete_point(FLAC__StreamMetadata *object, unsigned point_num)
+{
+	unsigned i;
+
+	FLAC__ASSERT(0 != object);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
+	FLAC__ASSERT(point_num < object->data.seek_table.num_points);
+
+	/* move all points > point_num backward one space */
+	for(i = point_num; i < object->data.seek_table.num_points-1; i++)
+		object->data.seek_table.points[i] = object->data.seek_table.points[i+1];
+
+	return FLAC__metadata_object_seektable_resize_points(object, object->data.seek_table.num_points-1);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_is_legal(const FLAC__StreamMetadata *object)
+{
+	FLAC__ASSERT(0 != object);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
+
+	return FLAC__format_seektable_is_legal(&object->data.seek_table);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_placeholders(FLAC__StreamMetadata *object, unsigned num)
+{
+	FLAC__ASSERT(0 != object);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
+
+	if(num > 0)
+		/* WATCHOUT: we rely on the fact that growing the array adds PLACEHOLDERS at the end */
+		return FLAC__metadata_object_seektable_resize_points(object, object->data.seek_table.num_points + num);
+	else
+		return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_point(FLAC__StreamMetadata *object, FLAC__uint64 sample_number)
+{
+	FLAC__StreamMetadata_SeekTable *seek_table;
+
+	FLAC__ASSERT(0 != object);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
+
+	seek_table = &object->data.seek_table;
+
+	if(!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + 1))
+		return false;
+
+	seek_table->points[seek_table->num_points - 1].sample_number = sample_number;
+	seek_table->points[seek_table->num_points - 1].stream_offset = 0;
+	seek_table->points[seek_table->num_points - 1].frame_samples = 0;
+
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_points(FLAC__StreamMetadata *object, FLAC__uint64 sample_numbers[], unsigned num)
+{
+	FLAC__ASSERT(0 != object);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
+	FLAC__ASSERT(0 != sample_numbers || num == 0);
+
+	if(num > 0) {
+		FLAC__StreamMetadata_SeekTable *seek_table = &object->data.seek_table;
+		unsigned i, j;
+
+		i = seek_table->num_points;
+
+		if(!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + num))
+			return false;
+
+		for(j = 0; j < num; i++, j++) {
+			seek_table->points[i].sample_number = sample_numbers[j];
+			seek_table->points[i].stream_offset = 0;
+			seek_table->points[i].frame_samples = 0;
+		}
+	}
+
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_points(FLAC__StreamMetadata *object, unsigned num, FLAC__uint64 total_samples)
+{
+	FLAC__ASSERT(0 != object);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
+	FLAC__ASSERT(total_samples > 0);
+
+	if(num > 0) {
+		FLAC__StreamMetadata_SeekTable *seek_table = &object->data.seek_table;
+		unsigned i, j;
+
+		i = seek_table->num_points;
+
+		if(!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + num))
+			return false;
+
+		for(j = 0; j < num; i++, j++) {
+			seek_table->points[i].sample_number = total_samples * (FLAC__uint64)j / (FLAC__uint64)num;
+			seek_table->points[i].stream_offset = 0;
+			seek_table->points[i].frame_samples = 0;
+		}
+	}
+
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_sort(FLAC__StreamMetadata *object, FLAC__bool compact)
+{
+	unsigned unique;
+
+	FLAC__ASSERT(0 != object);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
+
+	unique = FLAC__format_seektable_sort(&object->data.seek_table);
+
+	return !compact || FLAC__metadata_object_seektable_resize_points(object, unique);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_vendor_string(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy)
+{
+	return vorbiscomment_set_entry_(object, &object->data.vorbis_comment.vendor_string, &entry, copy);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_resize_comments(FLAC__StreamMetadata *object, unsigned new_num_comments)
+{
+	FLAC__ASSERT(0 != object);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+	if(0 == object->data.vorbis_comment.comments) {
+		FLAC__ASSERT(object->data.vorbis_comment.num_comments == 0);
+		if(0 == new_num_comments)
+			return true;
+		else if(0 == (object->data.vorbis_comment.comments = vorbiscomment_entry_array_new_(new_num_comments)))
+			return false;
+	}
+	else {
+		const unsigned old_size = object->data.vorbis_comment.num_comments * sizeof(FLAC__StreamMetadata_VorbisComment_Entry);
+		const unsigned new_size = new_num_comments * sizeof(FLAC__StreamMetadata_VorbisComment_Entry);
+
+		FLAC__ASSERT(object->data.vorbis_comment.num_comments > 0);
+
+		/* if shrinking, free the truncated entries */
+		if(new_num_comments < object->data.vorbis_comment.num_comments) {
+			unsigned i;
+			for(i = new_num_comments; i < object->data.vorbis_comment.num_comments; i++)
+				if(0 != object->data.vorbis_comment.comments[i].entry)
+					free(object->data.vorbis_comment.comments[i].entry);
+		}
+
+		if(new_size == 0) {
+			free(object->data.vorbis_comment.comments);
+			object->data.vorbis_comment.comments = 0;
+		}
+		else if(0 == (object->data.vorbis_comment.comments = (FLAC__StreamMetadata_VorbisComment_Entry*)realloc(object->data.vorbis_comment.comments, new_size)))
+			return false;
+
+		/* if growing, zero all the length/pointers of new elements */
+		if(new_size > old_size)
+			memset(object->data.vorbis_comment.comments + object->data.vorbis_comment.num_comments, 0, new_size - old_size);
+	}
+
+	object->data.vorbis_comment.num_comments = new_num_comments;
+
+	vorbiscomment_calculate_length_(object);
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_comment(FLAC__StreamMetadata *object, unsigned comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy)
+{
+	FLAC__ASSERT(0 != object);
+	FLAC__ASSERT(comment_num < object->data.vorbis_comment.num_comments);
+
+	return vorbiscomment_set_entry_(object, &object->data.vorbis_comment.comments[comment_num], &entry, copy);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_insert_comment(FLAC__StreamMetadata *object, unsigned comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy)
+{
+	FLAC__StreamMetadata_VorbisComment *vc;
+
+	FLAC__ASSERT(0 != object);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+	FLAC__ASSERT(comment_num <= object->data.vorbis_comment.num_comments);
+
+	vc = &object->data.vorbis_comment;
+
+	if(!FLAC__metadata_object_vorbiscomment_resize_comments(object, vc->num_comments+1))
+		return false;
+
+	/* move all comments >= comment_num forward one space */
+	memmove(&vc->comments[comment_num+1], &vc->comments[comment_num], sizeof(FLAC__StreamMetadata_VorbisComment_Entry)*(vc->num_comments-1-comment_num));
+	vc->comments[comment_num].length = 0;
+	vc->comments[comment_num].entry = 0;
+
+	return FLAC__metadata_object_vorbiscomment_set_comment(object, comment_num, entry, copy);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_delete_comment(FLAC__StreamMetadata *object, unsigned comment_num)
+{
+	FLAC__StreamMetadata_VorbisComment *vc;
+
+	FLAC__ASSERT(0 != object);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+	FLAC__ASSERT(comment_num < object->data.vorbis_comment.num_comments);
+
+	vc = &object->data.vorbis_comment;
+
+	/* free the comment at comment_num */
+	if(0 != vc->comments[comment_num].entry)
+		free(vc->comments[comment_num].entry);
+
+	/* move all comments > comment_num backward one space */
+	memmove(&vc->comments[comment_num], &vc->comments[comment_num+1], sizeof(FLAC__StreamMetadata_VorbisComment_Entry)*(vc->num_comments-comment_num-1));
+	vc->comments[vc->num_comments-1].length = 0;
+	vc->comments[vc->num_comments-1].entry = 0;
+
+	return FLAC__metadata_object_vorbiscomment_resize_comments(object, vc->num_comments-1);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_matches(const FLAC__StreamMetadata_VorbisComment_Entry *entry, const char *field_name, unsigned field_name_length)
+{
+	const FLAC__byte *eq = (FLAC__byte*)memchr(entry->entry, '=', entry->length);
+#if defined _MSC_VER || defined __MINGW32__
+#define FLAC__STRNCASECMP strnicmp
+#else
+#define FLAC__STRNCASECMP strncasecmp
+#endif
+	return (0 != eq && (unsigned)(eq-entry->entry) == field_name_length && 0 == FLAC__STRNCASECMP(field_name, (const char *)entry->entry, field_name_length));
+#undef FLAC__STRNCASECMP
+}
+
+FLAC_API int FLAC__metadata_object_vorbiscomment_find_entry_from(const FLAC__StreamMetadata *object, unsigned offset, const char *field_name)
+{
+	const unsigned field_name_length = strlen(field_name);
+	unsigned i;
+
+	FLAC__ASSERT(0 != object);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+	for(i = offset; i < object->data.vorbis_comment.num_comments; i++) {
+		if(FLAC__metadata_object_vorbiscomment_entry_matches(object->data.vorbis_comment.comments + i, field_name, field_name_length))
+			return (int)i;
+	}
+
+	return -1;
+}
+
+FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entry_matching(FLAC__StreamMetadata *object, const char *field_name)
+{
+	const unsigned field_name_length = strlen(field_name);
+	unsigned i;
+
+	FLAC__ASSERT(0 != object);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+	for(i = 0; i < object->data.vorbis_comment.num_comments; i++) {
+		if(FLAC__metadata_object_vorbiscomment_entry_matches(object->data.vorbis_comment.comments + i, field_name, field_name_length)) {
+			if(!FLAC__metadata_object_vorbiscomment_delete_comment(object, i))
+				return -1;
+			else
+				return 1;
+		}
+	}
+
+	return 0;
+}
+
+FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entries_matching(FLAC__StreamMetadata *object, const char *field_name)
+{
+	FLAC__bool ok = true;
+	unsigned matching = 0;
+	const unsigned field_name_length = strlen(field_name);
+	int i;
+
+	FLAC__ASSERT(0 != object);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+	/* must delete from end to start otherwise it will interfere with our iteration */
+	for(i = (int)object->data.vorbis_comment.num_comments - 1; ok && i >= 0; i--) {
+		if(FLAC__metadata_object_vorbiscomment_entry_matches(object->data.vorbis_comment.comments + i, field_name, field_name_length)) {
+			matching++;
+			ok &= FLAC__metadata_object_vorbiscomment_delete_comment(object, (unsigned)i);
+		}
+	}
+
+	return ok? (int)matching : -1;
+}
+
+FLAC_API FLAC__StreamMetadata_CueSheet_Track *FLAC__metadata_object_cuesheet_track_new()
+{
+	return (FLAC__StreamMetadata_CueSheet_Track*)calloc(1, sizeof(FLAC__StreamMetadata_CueSheet_Track));
+}
+
+FLAC_API FLAC__StreamMetadata_CueSheet_Track *FLAC__metadata_object_cuesheet_track_clone(const FLAC__StreamMetadata_CueSheet_Track *object)
+{
+	FLAC__StreamMetadata_CueSheet_Track *to;
+
+	FLAC__ASSERT(0 != object);
+
+	if(0 != (to = FLAC__metadata_object_cuesheet_track_new())) {
+		if(!copy_track_(to, object)) {
+			FLAC__metadata_object_cuesheet_track_delete(to);
+			return 0;
+		}
+	}
+
+	return to;
+}
+
+void FLAC__metadata_object_cuesheet_track_delete_data(FLAC__StreamMetadata_CueSheet_Track *object)
+{
+	FLAC__ASSERT(0 != object);
+
+	if(0 != object->indices) {
+		FLAC__ASSERT(object->num_indices > 0);
+		free(object->indices);
+	}
+}
+
+FLAC_API void FLAC__metadata_object_cuesheet_track_delete(FLAC__StreamMetadata_CueSheet_Track *object)
+{
+	FLAC__metadata_object_cuesheet_track_delete_data(object);
+	free(object);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_resize_indices(FLAC__StreamMetadata *object, unsigned track_num, unsigned new_num_indices)
+{
+	FLAC__StreamMetadata_CueSheet_Track *track;
+	FLAC__ASSERT(0 != object);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
+	FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks);
+
+	track = &object->data.cue_sheet.tracks[track_num];
+
+	if(0 == track->indices) {
+		FLAC__ASSERT(track->num_indices == 0);
+		if(0 == new_num_indices)
+			return true;
+		else if(0 == (track->indices = cuesheet_track_index_array_new_(new_num_indices)))
+			return false;
+	}
+	else {
+		const unsigned old_size = track->num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index);
+		const unsigned new_size = new_num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index);
+
+		FLAC__ASSERT(track->num_indices > 0);
+
+		if(new_size == 0) {
+			free(track->indices);
+			track->indices = 0;
+		}
+		else if(0 == (track->indices = (FLAC__StreamMetadata_CueSheet_Index*)realloc(track->indices, new_size)))
+			return false;
+
+		/* if growing, zero all the lengths/pointers of new elements */
+		if(new_size > old_size)
+			memset(track->indices + track->num_indices, 0, new_size - old_size);
+	}
+
+	track->num_indices = new_num_indices;
+
+	cuesheet_calculate_length_(object);
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_index(FLAC__StreamMetadata *object, unsigned track_num, unsigned index_num, FLAC__StreamMetadata_CueSheet_Index index)
+{
+	FLAC__StreamMetadata_CueSheet_Track *track;
+
+	FLAC__ASSERT(0 != object);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
+	FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks);
+	FLAC__ASSERT(index_num <= object->data.cue_sheet.tracks[track_num].num_indices);
+
+	track = &object->data.cue_sheet.tracks[track_num];
+
+	if(!FLAC__metadata_object_cuesheet_track_resize_indices(object, track_num, track->num_indices+1))
+		return false;
+
+	/* move all indices >= index_num forward one space */
+	memmove(&track->indices[index_num+1], &track->indices[index_num], sizeof(FLAC__StreamMetadata_CueSheet_Index)*(track->num_indices-1-index_num));
+
+	track->indices[index_num] = index;
+	cuesheet_calculate_length_(object);
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_blank_index(FLAC__StreamMetadata *object, unsigned track_num, unsigned index_num)
+{
+	FLAC__StreamMetadata_CueSheet_Index index;
+	memset(&index, 0, sizeof(index));
+	return FLAC__metadata_object_cuesheet_track_insert_index(object, track_num, index_num, index);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_delete_index(FLAC__StreamMetadata *object, unsigned track_num, unsigned index_num)
+{
+	FLAC__StreamMetadata_CueSheet_Track *track;
+
+	FLAC__ASSERT(0 != object);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
+	FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks);
+	FLAC__ASSERT(index_num < object->data.cue_sheet.tracks[track_num].num_indices);
+
+	track = &object->data.cue_sheet.tracks[track_num];
+
+	/* move all indices > index_num backward one space */
+	memmove(&track->indices[index_num], &track->indices[index_num+1], sizeof(FLAC__StreamMetadata_CueSheet_Index)*(track->num_indices-index_num-1));
+
+	FLAC__metadata_object_cuesheet_track_resize_indices(object, track_num, track->num_indices-1);
+	cuesheet_calculate_length_(object);
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_resize_tracks(FLAC__StreamMetadata *object, unsigned new_num_tracks)
+{
+	FLAC__ASSERT(0 != object);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
+
+	if(0 == object->data.cue_sheet.tracks) {
+		FLAC__ASSERT(object->data.cue_sheet.num_tracks == 0);
+		if(0 == new_num_tracks)
+			return true;
+		else if(0 == (object->data.cue_sheet.tracks = cuesheet_track_array_new_(new_num_tracks)))
+			return false;
+	}
+	else {
+		const unsigned old_size = object->data.cue_sheet.num_tracks * sizeof(FLAC__StreamMetadata_CueSheet_Track);
+		const unsigned new_size = new_num_tracks * sizeof(FLAC__StreamMetadata_CueSheet_Track);
+
+		FLAC__ASSERT(object->data.cue_sheet.num_tracks > 0);
+
+		/* if shrinking, free the truncated entries */
+		if(new_num_tracks < object->data.cue_sheet.num_tracks) {
+			unsigned i;
+			for(i = new_num_tracks; i < object->data.cue_sheet.num_tracks; i++)
+				if(0 != object->data.cue_sheet.tracks[i].indices)
+					free(object->data.cue_sheet.tracks[i].indices);
+		}
+
+		if(new_size == 0) {
+			free(object->data.cue_sheet.tracks);
+			object->data.cue_sheet.tracks = 0;
+		}
+		else if(0 == (object->data.cue_sheet.tracks = (FLAC__StreamMetadata_CueSheet_Track*)realloc(object->data.cue_sheet.tracks, new_size)))
+			return false;
+
+		/* if growing, zero all the lengths/pointers of new elements */
+		if(new_size > old_size)
+			memset(object->data.cue_sheet.tracks + object->data.cue_sheet.num_tracks, 0, new_size - old_size);
+	}
+
+	object->data.cue_sheet.num_tracks = new_num_tracks;
+
+	cuesheet_calculate_length_(object);
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_set_track(FLAC__StreamMetadata *object, unsigned track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy)
+{
+	FLAC__ASSERT(0 != object);
+	FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks);
+
+	return cuesheet_set_track_(object, object->data.cue_sheet.tracks + track_num, track, copy);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_track(FLAC__StreamMetadata *object, unsigned track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy)
+{
+	FLAC__StreamMetadata_CueSheet *cs;
+
+	FLAC__ASSERT(0 != object);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
+	FLAC__ASSERT(track_num <= object->data.cue_sheet.num_tracks);
+
+	cs = &object->data.cue_sheet;
+
+	if(!FLAC__metadata_object_cuesheet_resize_tracks(object, cs->num_tracks+1))
+		return false;
+
+	/* move all tracks >= track_num forward one space */
+	memmove(&cs->tracks[track_num+1], &cs->tracks[track_num], sizeof(FLAC__StreamMetadata_CueSheet_Track)*(cs->num_tracks-1-track_num));
+	cs->tracks[track_num].num_indices = 0;
+	cs->tracks[track_num].indices = 0;
+
+	return FLAC__metadata_object_cuesheet_set_track(object, track_num, track, copy);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_blank_track(FLAC__StreamMetadata *object, unsigned track_num)
+{
+	FLAC__StreamMetadata_CueSheet_Track track;
+	memset(&track, 0, sizeof(track));
+	return FLAC__metadata_object_cuesheet_insert_track(object, track_num, &track, /*copy=*/false);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_delete_track(FLAC__StreamMetadata *object, unsigned track_num)
+{
+	FLAC__StreamMetadata_CueSheet *cs;
+
+	FLAC__ASSERT(0 != object);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
+	FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks);
+
+	cs = &object->data.cue_sheet;
+
+	/* free the track at track_num */
+	if(0 != cs->tracks[track_num].indices)
+		free(cs->tracks[track_num].indices);
+
+	/* move all tracks > track_num backward one space */
+	memmove(&cs->tracks[track_num], &cs->tracks[track_num+1], sizeof(FLAC__StreamMetadata_CueSheet_Track)*(cs->num_tracks-track_num-1));
+	cs->tracks[cs->num_tracks-1].num_indices = 0;
+	cs->tracks[cs->num_tracks-1].indices = 0;
+
+	return FLAC__metadata_object_cuesheet_resize_tracks(object, cs->num_tracks-1);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_is_legal(const FLAC__StreamMetadata *object, FLAC__bool check_cd_da_subset, const char **violation)
+{
+	FLAC__ASSERT(0 != object);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
+
+	return FLAC__format_cuesheet_is_legal(&object->data.cue_sheet, check_cd_da_subset, violation);
+}
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/mkfile
@@ -1,0 +1,28 @@
+</$objtype/mkfile
+
+LIB=libFLAC.a$O
+
+OFILES=\
+	bitbuffer.$O\
+	bitmath.$O\
+	cpu.$O\
+	crc.$O\
+	fixed.$O\
+	format.$O\
+	lpc.$O\
+	md5.$O\
+	memory.$O\
+	metadata_iterators.$O\
+	metadata_object.$O\
+	file_encoder.$O\
+	file_decoder.$O\
+	seekable_stream_encoder.$O\
+	seekable_stream_decoder.$O\
+	stream_encoder.$O\
+	stream_decoder.$O\
+	stream_encoder_framing.$O\
+
+CC=pcc
+CFLAGS=-I. -DVERSION="1.1.1" -DPlan9 -DFLAC__NO_NASM -DFLAC__ALIGN_MALLOC_DATA -D_BSD_EXTENSION -D_POSIX_SOURCE -c
+
+</sys/src/cmd/mklib
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/private/all.h
@@ -1,0 +1,47 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__ALL_H
+#define FLAC__PRIVATE__ALL_H
+
+#include "bitbuffer.h"
+#include "bitmath.h"
+#include "cpu.h"
+#include "crc.h"
+#include "fixed.h"
+#include "format.h"
+#include "lpc.h"
+#include "md5.h"
+#include "memory.h"
+#include "metadata.h"
+#include "stream_encoder_framing.h"
+
+#endif
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/private/bitbuffer.h
@@ -1,0 +1,159 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__BITBUFFER_H
+#define FLAC__PRIVATE__BITBUFFER_H
+
+#include <stdio.h> /* for FILE */
+#include "FLAC/ordinals.h"
+
+/* @@@ This should be configurable. Valid values are currently 8 and 32. */
+/* @@@ WATCHOUT!  do not use 32 with a little endian system yet. */
+#define FLAC__BITS_PER_BLURB 8
+
+#if FLAC__BITS_PER_BLURB == 8
+typedef FLAC__byte FLAC__blurb;
+#elif FLAC__BITS_PER_BLURB == 32
+typedef FLAC__uint32 FLAC__blurb;
+#else
+/* ERROR, only sizes of 8 and 32 are supported */
+#endif
+
+/*
+ * opaque structure definition
+ */
+struct FLAC__BitBuffer;
+typedef struct FLAC__BitBuffer FLAC__BitBuffer;
+
+/*
+ * construction, deletion, initialization, cloning functions
+ */
+FLAC__BitBuffer *FLAC__bitbuffer_new();
+void FLAC__bitbuffer_delete(FLAC__BitBuffer *bb);
+FLAC__bool FLAC__bitbuffer_init(FLAC__BitBuffer *bb);
+FLAC__bool FLAC__bitbuffer_init_from(FLAC__BitBuffer *bb, const FLAC__byte buffer[], unsigned bytes);
+FLAC__bool FLAC__bitbuffer_concatenate_aligned(FLAC__BitBuffer *dest, const FLAC__BitBuffer *src);
+void FLAC__bitbuffer_free(FLAC__BitBuffer *bb); /* does not 'free(buffer)' */
+FLAC__bool FLAC__bitbuffer_clear(FLAC__BitBuffer *bb);
+FLAC__bool FLAC__bitbuffer_clone(FLAC__BitBuffer *dest, const FLAC__BitBuffer *src);
+
+/*
+ * CRC functions
+ */
+void FLAC__bitbuffer_reset_read_crc16(FLAC__BitBuffer *bb, FLAC__uint16 seed);
+FLAC__uint16 FLAC__bitbuffer_get_read_crc16(FLAC__BitBuffer *bb);
+FLAC__uint16 FLAC__bitbuffer_get_write_crc16(const FLAC__BitBuffer *bb);
+FLAC__byte FLAC__bitbuffer_get_write_crc8(const FLAC__BitBuffer *bb);
+
+/*
+ * info functions
+ */
+FLAC__bool FLAC__bitbuffer_is_byte_aligned(const FLAC__BitBuffer *bb);
+FLAC__bool FLAC__bitbuffer_is_consumed_byte_aligned(const FLAC__BitBuffer *bb);
+unsigned FLAC__bitbuffer_bits_left_for_byte_alignment(const FLAC__BitBuffer *bb);
+unsigned FLAC__bitbuffer_get_input_bytes_unconsumed(const FLAC__BitBuffer *bb); /* do not call unless byte-aligned */
+
+/*
+ * direct buffer access
+ */
+void FLAC__bitbuffer_get_buffer(FLAC__BitBuffer *bb, const FLAC__byte **buffer, unsigned *bytes);
+void FLAC__bitbuffer_release_buffer(FLAC__BitBuffer *bb);
+
+/*
+ * write functions
+ */
+FLAC__bool FLAC__bitbuffer_write_zeroes(FLAC__BitBuffer *bb, unsigned bits);
+FLAC__bool FLAC__bitbuffer_write_raw_uint32(FLAC__BitBuffer *bb, FLAC__uint32 val, unsigned bits);
+FLAC__bool FLAC__bitbuffer_write_raw_int32(FLAC__BitBuffer *bb, FLAC__int32 val, unsigned bits);
+FLAC__bool FLAC__bitbuffer_write_raw_uint64(FLAC__BitBuffer *bb, FLAC__uint64 val, unsigned bits);
+#if 0 /* UNUSED */
+FLAC__bool FLAC__bitbuffer_write_raw_int64(FLAC__BitBuffer *bb, FLAC__int64 val, unsigned bits);
+#endif
+FLAC__bool FLAC__bitbuffer_write_raw_uint32_little_endian(FLAC__BitBuffer *bb, FLAC__uint32 val); /*only for bits=32*/
+FLAC__bool FLAC__bitbuffer_write_byte_block(FLAC__BitBuffer *bb, const FLAC__byte vals[], unsigned nvals);
+FLAC__bool FLAC__bitbuffer_write_unary_unsigned(FLAC__BitBuffer *bb, unsigned val);
+unsigned FLAC__bitbuffer_rice_bits(int val, unsigned parameter);
+#if 0 /* UNUSED */
+unsigned FLAC__bitbuffer_golomb_bits_signed(int val, unsigned parameter);
+unsigned FLAC__bitbuffer_golomb_bits_unsigned(unsigned val, unsigned parameter);
+#endif
+#ifdef FLAC__SYMMETRIC_RICE
+FLAC__bool FLAC__bitbuffer_write_symmetric_rice_signed(FLAC__BitBuffer *bb, int val, unsigned parameter);
+#if 0 /* UNUSED */
+FLAC__bool FLAC__bitbuffer_write_symmetric_rice_signed_guarded(FLAC__BitBuffer *bb, int val, unsigned parameter, unsigned max_bits, FLAC__bool *overflow);
+#endif
+FLAC__bool FLAC__bitbuffer_write_symmetric_rice_signed_escape(FLAC__BitBuffer *bb, int val, unsigned parameter);
+#endif
+FLAC__bool FLAC__bitbuffer_write_rice_signed(FLAC__BitBuffer *bb, int val, unsigned parameter);
+#if 0 /* UNUSED */
+FLAC__bool FLAC__bitbuffer_write_rice_signed_guarded(FLAC__BitBuffer *bb, int val, unsigned parameter, unsigned max_bits, FLAC__bool *overflow);
+#endif
+#if 0 /* UNUSED */
+FLAC__bool FLAC__bitbuffer_write_golomb_signed(FLAC__BitBuffer *bb, int val, unsigned parameter);
+FLAC__bool FLAC__bitbuffer_write_golomb_signed_guarded(FLAC__BitBuffer *bb, int val, unsigned parameter, unsigned max_bits, FLAC__bool *overflow);
+FLAC__bool FLAC__bitbuffer_write_golomb_unsigned(FLAC__BitBuffer *bb, unsigned val, unsigned parameter);
+FLAC__bool FLAC__bitbuffer_write_golomb_unsigned_guarded(FLAC__BitBuffer *bb, unsigned val, unsigned parameter, unsigned max_bits, FLAC__bool *overflow);
+#endif
+FLAC__bool FLAC__bitbuffer_write_utf8_uint32(FLAC__BitBuffer *bb, FLAC__uint32 val);
+FLAC__bool FLAC__bitbuffer_write_utf8_uint64(FLAC__BitBuffer *bb, FLAC__uint64 val);
+FLAC__bool FLAC__bitbuffer_zero_pad_to_byte_boundary(FLAC__BitBuffer *bb);
+
+/*
+ * read functions
+ */
+FLAC__bool FLAC__bitbuffer_peek_bit(FLAC__BitBuffer *bb, unsigned *val, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data);
+FLAC__bool FLAC__bitbuffer_read_bit(FLAC__BitBuffer *bb, unsigned *val, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data);
+FLAC__bool FLAC__bitbuffer_read_bit_to_uint32(FLAC__BitBuffer *bb, FLAC__uint32 *val, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data);
+FLAC__bool FLAC__bitbuffer_read_bit_to_uint64(FLAC__BitBuffer *bb, FLAC__uint64 *val, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data);
+FLAC__bool FLAC__bitbuffer_read_raw_uint32(FLAC__BitBuffer *bb, FLAC__uint32 *val, const unsigned bits, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data);
+FLAC__bool FLAC__bitbuffer_read_raw_int32(FLAC__BitBuffer *bb, FLAC__int32 *val, const unsigned bits, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data);
+FLAC__bool FLAC__bitbuffer_read_raw_uint64(FLAC__BitBuffer *bb, FLAC__uint64 *val, const unsigned bits, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data);
+#if 0 /* UNUSED */
+FLAC__bool FLAC__bitbuffer_read_raw_int64(FLAC__BitBuffer *bb, FLAC__int64 *val, const unsigned bits, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data);
+#endif
+FLAC__bool FLAC__bitbuffer_read_raw_uint32_little_endian(FLAC__BitBuffer *bb, FLAC__uint32 *val, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data); /*only for bits=32*/
+FLAC__bool FLAC__bitbuffer_skip_bits_no_crc(FLAC__BitBuffer *bb, unsigned bits, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data); /* WATCHOUT: does not CRC the skipped data! */ /*@@@@ add to unit tests */
+FLAC__bool FLAC__bitbuffer_read_byte_block_aligned_no_crc(FLAC__BitBuffer *bb, FLAC__byte *val, unsigned nvals, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data); /* val may be 0 to skip bytes instead of reading them */ /* WATCHOUT: does not CRC the read data! */
+FLAC__bool FLAC__bitbuffer_read_unary_unsigned(FLAC__BitBuffer *bb, unsigned *val, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data);
+#ifdef FLAC__SYMMETRIC_RICE
+FLAC__bool FLAC__bitbuffer_read_symmetric_rice_signed(FLAC__BitBuffer *bb, int *val, unsigned parameter, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data);
+#endif
+FLAC__bool FLAC__bitbuffer_read_rice_signed(FLAC__BitBuffer *bb, int *val, unsigned parameter, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data);
+FLAC__bool FLAC__bitbuffer_read_rice_signed_block(FLAC__BitBuffer *bb, int vals[], unsigned nvals, unsigned parameter, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data);
+#if 0 /* UNUSED */
+FLAC__bool FLAC__bitbuffer_read_golomb_signed(FLAC__BitBuffer *bb, int *val, unsigned parameter, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data);
+FLAC__bool FLAC__bitbuffer_read_golomb_unsigned(FLAC__BitBuffer *bb, unsigned *val, unsigned parameter, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data);
+#endif
+FLAC__bool FLAC__bitbuffer_read_utf8_uint32(FLAC__BitBuffer *bb, FLAC__uint32 *val, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data, FLAC__byte *raw, unsigned *rawlen);
+FLAC__bool FLAC__bitbuffer_read_utf8_uint64(FLAC__BitBuffer *bb, FLAC__uint64 *val, FLAC__bool (*read_callback)(FLAC__byte buffer[], unsigned *bytes, void *client_data), void *client_data, FLAC__byte *raw, unsigned *rawlen);
+void FLAC__bitbuffer_dump(const FLAC__BitBuffer *bb, FILE *out);
+
+#endif
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/private/bitmath.h
@@ -1,0 +1,41 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001,2002,2003,2004  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__BITMATH_H
+#define FLAC__PRIVATE__BITMATH_H
+
+#include "FLAC/ordinals.h"
+
+unsigned FLAC__bitmath_ilog2(unsigned v);
+unsigned FLAC__bitmath_silog2(int v);
+unsigned FLAC__bitmath_silog2_wide(FLAC__int64 v);
+
+#endif
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/private/cpu.h
@@ -1,0 +1,93 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001,2002,2003,2004  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__CPU_H
+#define FLAC__PRIVATE__CPU_H
+
+#include "FLAC/ordinals.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+typedef enum {
+	FLAC__CPUINFO_TYPE_IA32,
+	FLAC__CPUINFO_TYPE_PPC,
+	FLAC__CPUINFO_TYPE_UNKNOWN
+} FLAC__CPUInfo_Type;
+
+typedef struct {
+	FLAC__bool cmov;
+	FLAC__bool mmx;
+	FLAC__bool fxsr;
+	FLAC__bool sse;
+	FLAC__bool sse2;
+	FLAC__bool _3dnow;
+	FLAC__bool ext3dnow;
+	FLAC__bool extmmx;
+} FLAC__CPUInfo_IA32;
+
+typedef struct {
+	FLAC__bool altivec;
+} FLAC__CPUInfo_PPC;
+
+extern const unsigned FLAC__CPUINFO_IA32_CPUID_CMOV;
+extern const unsigned FLAC__CPUINFO_IA32_CPUID_MMX;
+extern const unsigned FLAC__CPUINFO_IA32_CPUID_FXSR;
+extern const unsigned FLAC__CPUINFO_IA32_CPUID_SSE;
+extern const unsigned FLAC__CPUINFO_IA32_CPUID_SSE2;
+
+extern const unsigned FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_3DNOW;
+extern const unsigned FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_EXT3DNOW;
+extern const unsigned FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_EXTMMX;
+
+typedef struct {
+	FLAC__bool use_asm;
+	FLAC__CPUInfo_Type type;
+	union {
+		FLAC__CPUInfo_IA32 ia32;
+		FLAC__CPUInfo_PPC ppc;
+	} data;
+} FLAC__CPUInfo;
+
+void FLAC__cpu_info(FLAC__CPUInfo *info);
+
+#ifndef FLAC__NO_ASM
+#ifdef FLAC__CPU_IA32
+#ifdef FLAC__HAS_NASM
+unsigned FLAC__cpu_info_asm_ia32();
+unsigned FLAC__cpu_info_extended_amd_asm_ia32();
+unsigned FLAC__cpu_info_sse_test_asm_ia32();
+#endif
+#endif
+#endif
+
+#endif
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/private/crc.h
@@ -1,0 +1,57 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#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 + x^0
+** init = 0
+*/
+extern FLAC__byte const FLAC__crc8_table[256];
+#define FLAC__CRC8_UPDATE(data, crc) (crc) = FLAC__crc8_table[(crc) ^ (data)];
+void FLAC__crc8_update(const FLAC__byte data, FLAC__uint8 *crc);
+void FLAC__crc8_update_block(const FLAC__byte *data, unsigned len, FLAC__uint8 *crc);
+FLAC__uint8 FLAC__crc8(const FLAC__byte *data, unsigned len);
+
+/* 16 bit CRC generator, MSB shifted first
+** polynomial = x^16 + x^15 + x^2 + x^0
+** init = 0
+*/
+extern FLAC__uint16 FLAC__crc16_table[256];
+#define FLAC__CRC16_UPDATE(data, crc) (crc) = ((crc)<<8) ^ FLAC__crc16_table[((crc)>>8) ^ (data)];
+void FLAC__crc16_update(const FLAC__byte data, FLAC__uint16 *crc);
+void FLAC__crc16_update_block(const FLAC__byte *data, unsigned len, FLAC__uint16 *crc);
+FLAC__uint16 FLAC__crc16(const FLAC__byte *data, unsigned len);
+
+#endif
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/private/fixed.h
@@ -1,0 +1,91 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__FIXED_H
+#define FLAC__PRIVATE__FIXED_H
+
+#include "FLAC/format.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/*
+ *	FLAC__fixed_compute_best_predictor()
+ *	--------------------------------------------------------------------
+ *	Compute the best fixed predictor and the expected bits-per-sample
+ *  of the residual signal for each order.  The _wide() version uses
+ *  64-bit integers which is statistically necessary when bits-per-
+ *  sample + log2(blocksize) > 30
+ *
+ *	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 FLAC__int32 data[], unsigned data_len, FLAC__real residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+#ifndef FLAC__NO_ASM
+#ifdef FLAC__CPU_IA32
+#ifdef FLAC__HAS_NASM
+unsigned FLAC__fixed_compute_best_predictor_asm_ia32_mmx_cmov(const FLAC__int32 data[], unsigned data_len, FLAC__real residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+#endif
+#endif
+#endif
+unsigned FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], unsigned data_len, FLAC__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 FLAC__int32 data[], unsigned data_len, unsigned order, FLAC__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 FLAC__int32 residual[], unsigned data_len, unsigned order, FLAC__int32 data[]);
+
+#endif
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/private/format.h
@@ -1,0 +1,44 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__FORMAT_H
+#define FLAC__PRIVATE__FORMAT_H
+
+#include "FLAC/format.h"
+
+unsigned FLAC__format_get_max_rice_partition_order(unsigned blocksize, unsigned predictor_order);
+unsigned FLAC__format_get_max_rice_partition_order_from_blocksize(unsigned blocksize);
+unsigned FLAC__format_get_max_rice_partition_order_from_blocksize_limited_max_and_predictor_order(unsigned limit, unsigned blocksize, unsigned predictor_order);
+void FLAC__format_entropy_coding_method_partitioned_rice_contents_init(FLAC__EntropyCodingMethod_PartitionedRiceContents *object);
+void FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(FLAC__EntropyCodingMethod_PartitionedRiceContents *object);
+FLAC__bool FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(FLAC__EntropyCodingMethod_PartitionedRiceContents *object, unsigned max_partition_order);
+
+#endif
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/private/lpc.h
@@ -1,0 +1,188 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__LPC_H
+#define FLAC__PRIVATE__LPC_H
+
+#include "FLAC/format.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/*
+ *	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 FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]);
+#ifndef FLAC__NO_ASM
+#ifdef FLAC__CPU_IA32
+#ifdef FLAC__HAS_NASM
+void FLAC__lpc_compute_autocorrelation_asm_ia32(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_4(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_8(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_12(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_asm_ia32_3dnow(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]);
+#endif
+#endif
+
+/*
+ *	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 FLAC__real autoc[], unsigned max_order, FLAC__real lp_coeff[][FLAC__MAX_LPC_ORDER], FLAC__real error[]);
+
+/*
+ *	FLAC__lpc_quantize_coefficients()
+ *	--------------------------------------------------------------------
+ *	Quantizes the LP coefficients.  NOTE: precision + bits_per_sample
+ *	must be less than 32 (sizeof(FLAC__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
+ *	OUT qlp_coeff[0,order-1]  quantized coefficients
+ *	OUT shift                 # of bits to shift right to get approximated
+ *	                          LP coefficients.  NOTE: could be negative.
+ *	RETURN 0 => quantization OK
+ *	       1 => coefficients require too much shifting for *shift to
+ *              fit in the LPC subframe header.  'shift' is unset.
+ *         2 => coefficients are all zero, which is bad.  'shift' is
+ *              unset.
+ */
+int FLAC__lpc_quantize_coefficients(const FLAC__real lp_coeff[], unsigned order, unsigned precision, FLAC__int32 qlp_coeff[], int *shift);
+
+/*
+ *	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 FLAC__int32 data[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]);
+void FLAC__lpc_compute_residual_from_qlp_coefficients_wide(const FLAC__int32 data[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]);
+#ifndef FLAC__NO_ASM
+#ifdef FLAC__CPU_IA32
+#ifdef FLAC__HAS_NASM
+void FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32(const FLAC__int32 data[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]);
+void FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32_mmx(const FLAC__int32 data[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]);
+#endif
+#endif
+#endif
+
+/*
+ *	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 FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]);
+void FLAC__lpc_restore_signal_wide(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]);
+#ifndef FLAC__NO_ASM
+#ifdef FLAC__CPU_IA32
+#ifdef FLAC__HAS_NASM
+void FLAC__lpc_restore_signal_asm_ia32(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]);
+void FLAC__lpc_restore_signal_asm_ia32_mmx(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]);
+#endif
+#elif defined FLAC__CPU_PPC
+void FLAC__lpc_restore_signal_asm_ppc_altivec_16(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]);
+void FLAC__lpc_restore_signal_asm_ppc_altivec_16_order8(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]);
+#endif
+#endif
+#endif
+
+/*
+ *	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
+ */
+FLAC__real FLAC__lpc_compute_expected_bits_per_residual_sample(FLAC__real lpc_error, unsigned total_samples);
+FLAC__real FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(FLAC__real lpc_error, double error_scale);
+
+/*
+ *	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 FLAC__real lpc_error[], unsigned max_order, unsigned total_samples, unsigned bits_per_signal_sample);
+
+#endif
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/private/md5.h
@@ -1,0 +1,54 @@
+/*
+ * This is the header file for the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest.  This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ *
+ * Changed so as no longer to depend on Colin Plumb's `usual.h'
+ * header definitions; now uses stuff from dpkg's config.h
+ *  - Ian Jackson <[email protected]>.
+ * Still in the public domain.
+ *
+ * Josh Coalson: made some changes to integrate with libFLAC.
+ * Still in the public domain.
+ */
+
+#ifndef FLAC__PRIVATE__MD5_H
+#define FLAC__PRIVATE__MD5_H
+
+#define md5byte unsigned char
+
+/*
+ * Due to an unholy abomination in libOggFLAC (it requires access to
+ * these internal MD5 functions) we have to #include "FLAC/export.h"
+ * and export them when building a DLL
+ */
+#include "FLAC/export.h"
+#include "FLAC/ordinals.h"
+
+struct FLAC__MD5Context {
+	FLAC__uint32 buf[4];
+	FLAC__uint32 bytes[2];
+	FLAC__uint32 in[16];
+	FLAC__byte *internal_buf;
+	unsigned capacity;
+};
+
+FLAC_API void FLAC__MD5Init(struct FLAC__MD5Context *context);
+FLAC_API void FLAC__MD5Update(struct FLAC__MD5Context *context, md5byte const *buf, unsigned len);
+FLAC_API void FLAC__MD5Final(md5byte digest[16], struct FLAC__MD5Context *context);
+void FLAC__MD5Transform(FLAC__uint32 buf[4], FLAC__uint32 const in[16]);
+
+FLAC_API FLAC__bool FLAC__MD5Accumulate(struct FLAC__MD5Context *ctx, const FLAC__int32 * const signal[], unsigned channels, unsigned samples, unsigned bytes_per_sample);
+
+#endif /* !MD5_H */
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/private/memory.h
@@ -1,0 +1,49 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001,2002,2003,2004  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__MEMORY_H
+#define FLAC__PRIVATE__MEMORY_H
+
+#include <stdlib.h> /* for size_t */
+
+#include "FLAC/ordinals.h" /* for FLAC__bool */
+
+/* Returns the unaligned address returned by malloc.
+ * Use free() on this address to deallocate.
+ */
+void *FLAC__memory_alloc_aligned(size_t bytes, void **aligned_address);
+FLAC__bool FLAC__memory_alloc_aligned_int32_array(unsigned elements, FLAC__int32 **unaligned_pointer, FLAC__int32 **aligned_pointer);
+FLAC__bool FLAC__memory_alloc_aligned_uint32_array(unsigned elements, FLAC__uint32 **unaligned_pointer, FLAC__uint32 **aligned_pointer);
+FLAC__bool FLAC__memory_alloc_aligned_uint64_array(unsigned elements, FLAC__uint64 **unaligned_pointer, FLAC__uint64 **aligned_pointer);
+FLAC__bool FLAC__memory_alloc_aligned_unsigned_array(unsigned elements, unsigned **unaligned_pointer, unsigned **aligned_pointer);
+FLAC__bool FLAC__memory_alloc_aligned_real_array(unsigned elements, FLAC__real **unaligned_pointer, FLAC__real **aligned_pointer);
+
+#endif
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/private/metadata.h
@@ -1,0 +1,40 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2002,2003,2004  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__METADATA_H
+#define FLAC__PRIVATE__METADATA_H
+
+#include "FLAC/metadata.h"
+
+void FLAC__metadata_object_delete_data(FLAC__StreamMetadata *object);
+void FLAC__metadata_object_cuesheet_track_delete_data(FLAC__StreamMetadata_CueSheet_Track *object);
+
+#endif
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/private/stream_encoder_framing.h
@@ -1,0 +1,45 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__STREAM_ENCODER_FRAMING_H
+#define FLAC__PRIVATE__STREAM_ENCODER_FRAMING_H
+
+#include "FLAC/format.h"
+#include "bitbuffer.h"
+
+FLAC__bool FLAC__add_metadata_block(const FLAC__StreamMetadata *metadata, FLAC__BitBuffer *bb);
+FLAC__bool FLAC__frame_add_header(const FLAC__FrameHeader *header, FLAC__bool streamable_subset, FLAC__BitBuffer *bb);
+FLAC__bool FLAC__subframe_add_constant(const FLAC__Subframe_Constant *subframe, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitBuffer *bb);
+FLAC__bool FLAC__subframe_add_fixed(const FLAC__Subframe_Fixed *subframe, unsigned residual_samples, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitBuffer *bb);
+FLAC__bool FLAC__subframe_add_lpc(const FLAC__Subframe_LPC *subframe, unsigned residual_samples, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitBuffer *bb);
+FLAC__bool FLAC__subframe_add_verbatim(const FLAC__Subframe_Verbatim *subframe, unsigned samples, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitBuffer *bb);
+
+#endif
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/protected/all.h
@@ -1,0 +1,42 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001,2002,2003,2004  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PROTECTED__ALL_H
+#define FLAC__PROTECTED__ALL_H
+
+#include "file_decoder.h"
+#include "file_encoder.h"
+#include "seekable_stream_decoder.h"
+#include "seekable_stream_encoder.h"
+#include "stream_decoder.h"
+#include "stream_encoder.h"
+
+#endif
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/protected/file_decoder.h
@@ -1,0 +1,41 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PROTECTED__FILE_DECODER_H
+#define FLAC__PROTECTED__FILE_DECODER_H
+
+#include "FLAC/file_decoder.h"
+
+typedef struct FLAC__FileDecoderProtected {
+	FLAC__FileDecoderState state;
+} FLAC__FileDecoderProtected;
+
+#endif
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/protected/file_encoder.h
@@ -1,0 +1,41 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001,2002,2003,2004  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PROTECTED__FILE_ENCODER_H
+#define FLAC__PROTECTED__FILE_ENCODER_H
+
+#include "FLAC/file_encoder.h"
+
+typedef struct FLAC__FileEncoderProtected {
+	FLAC__FileEncoderState state;
+} FLAC__FileEncoderProtected;
+
+#endif
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/protected/seekable_stream_decoder.h
@@ -1,0 +1,42 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PROTECTED__SEEKABLE_STREAM_DECODER_H
+#define FLAC__PROTECTED__SEEKABLE_STREAM_DECODER_H
+
+#include "FLAC/seekable_stream_decoder.h"
+
+typedef struct FLAC__SeekableStreamDecoderProtected {
+	FLAC__bool md5_checking; /* if true, generate MD5 signature of decoded data and compare against signature in the STREAMINFO metadata block */
+	FLAC__SeekableStreamDecoderState state;
+} FLAC__SeekableStreamDecoderProtected;
+
+#endif
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/protected/seekable_stream_encoder.h
@@ -1,0 +1,42 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2002,2003,2004  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PROTECTED__SEEKABLE_STREAM_ENCODER_H
+#define FLAC__PROTECTED__SEEKABLE_STREAM_ENCODER_H
+
+#include "FLAC/seekable_stream_encoder.h"
+
+typedef struct FLAC__SeekableStreamEncoderProtected {
+	FLAC__SeekableStreamEncoderState state;
+	FLAC__uint64 streaminfo_offset, seektable_offset, audio_offset;
+} FLAC__SeekableStreamEncoderProtected;
+
+#endif
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/protected/stream_decoder.h
@@ -1,0 +1,51 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PROTECTED__STREAM_DECODER_H
+#define FLAC__PROTECTED__STREAM_DECODER_H
+
+#include "FLAC/stream_decoder.h"
+
+typedef struct FLAC__StreamDecoderProtected {
+	FLAC__StreamDecoderState state;
+	unsigned channels;
+	FLAC__ChannelAssignment channel_assignment;
+	unsigned bits_per_sample;
+	unsigned sample_rate; /* in Hz */
+	unsigned blocksize; /* in samples (per channel) */
+} FLAC__StreamDecoderProtected;
+
+/*
+ * return the number of input bytes consumed
+ */
+unsigned FLAC__stream_decoder_get_input_bytes_unconsumed(const FLAC__StreamDecoder *decoder);
+
+#endif
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/protected/stream_encoder.h
@@ -1,0 +1,60 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001,2002,2003,2004  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PROTECTED__STREAM_ENCODER_H
+#define FLAC__PROTECTED__STREAM_ENCODER_H
+
+#include "FLAC/stream_encoder.h"
+
+typedef struct FLAC__StreamEncoderProtected {
+	FLAC__StreamEncoderState state;
+	FLAC__bool verify;
+	FLAC__bool streamable_subset;
+	FLAC__bool do_mid_side_stereo;
+	FLAC__bool loose_mid_side_stereo;
+	unsigned channels;
+	unsigned bits_per_sample;
+	unsigned sample_rate;
+	unsigned blocksize;
+	unsigned max_lpc_order;
+	unsigned qlp_coeff_precision;
+	FLAC__bool do_qlp_coeff_prec_search;
+	FLAC__bool do_exhaustive_model_search;
+	FLAC__bool do_escape_coding;
+	unsigned min_residual_partition_order;
+	unsigned max_residual_partition_order;
+	unsigned rice_parameter_search_dist;
+	FLAC__uint64 total_samples_estimate;
+	FLAC__StreamMetadata **metadata;
+	unsigned num_metadata_blocks;
+} FLAC__StreamEncoderProtected;
+
+#endif
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/seekable_stream_decoder.c
@@ -1,0 +1,1087 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h> /* for calloc() */
+#include <string.h> /* for memcpy()/memcmp() */
+#include "FLAC/assert.h"
+#include "protected/seekable_stream_decoder.h"
+#include "protected/stream_decoder.h"
+#include "private/md5.h"
+
+/* adjust for compilers that can't understand using LLU suffix for uint64_t literals */
+#ifdef _MSC_VER
+#define FLAC__U64L(x) x
+#else
+#define FLAC__U64L(x) x##LLU
+#endif
+
+/***********************************************************************
+ *
+ * Private class method prototypes
+ *
+ ***********************************************************************/
+
+static void set_defaults_(FLAC__SeekableStreamDecoder *decoder);
+static FLAC__StreamDecoderReadStatus read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data);
+static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const 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 FLAC__bool seek_to_absolute_sample_(FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 stream_length, FLAC__uint64 target_sample);
+
+/***********************************************************************
+ *
+ * Private class data
+ *
+ ***********************************************************************/
+
+typedef struct FLAC__SeekableStreamDecoderPrivate {
+	FLAC__SeekableStreamDecoderReadCallback read_callback;
+	FLAC__SeekableStreamDecoderSeekCallback seek_callback;
+	FLAC__SeekableStreamDecoderTellCallback tell_callback;
+	FLAC__SeekableStreamDecoderLengthCallback length_callback;
+	FLAC__SeekableStreamDecoderEofCallback eof_callback;
+	FLAC__SeekableStreamDecoderWriteCallback write_callback;
+	FLAC__SeekableStreamDecoderMetadataCallback metadata_callback;
+	FLAC__SeekableStreamDecoderErrorCallback error_callback;
+	void *client_data;
+	FLAC__StreamDecoder *stream_decoder;
+	FLAC__bool do_md5_checking; /* initially gets protected_->md5_checking but is turned off after a seek */
+	struct FLAC__MD5Context md5context;
+	FLAC__byte stored_md5sum[16]; /* this is what is stored in the metadata */
+	FLAC__byte computed_md5sum[16]; /* this is the sum we computed from the decoded data */
+	/* the rest of these are only used for seeking: */
+	FLAC__StreamMetadata_StreamInfo stream_info; /* we keep this around so we can figure out how to seek quickly */
+	const FLAC__StreamMetadata_SeekTable *seek_table; /* we hold a pointer to the stream decoder's seek table for the same reason */
+	/* Since we always want to see the STREAMINFO and SEEK_TABLE blocks at this level, we need some extra flags to keep track of whether they should be passed on up through the metadata_callback */
+	FLAC__bool ignore_stream_info_block;
+	FLAC__bool ignore_seek_table_block;
+	FLAC__Frame last_frame; /* holds the info of the last frame we seeked to */
+	FLAC__uint64 target_sample;
+} FLAC__SeekableStreamDecoderPrivate;
+
+/***********************************************************************
+ *
+ * Public static class data
+ *
+ ***********************************************************************/
+
+FLAC_API const char * const FLAC__SeekableStreamDecoderStateString[] = {
+	"FLAC__SEEKABLE_STREAM_DECODER_OK",
+	"FLAC__SEEKABLE_STREAM_DECODER_SEEKING",
+	"FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM",
+	"FLAC__SEEKABLE_STREAM_DECODER_MEMORY_ALLOCATION_ERROR",
+	"FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR",
+	"FLAC__SEEKABLE_STREAM_DECODER_READ_ERROR",
+	"FLAC__SEEKABLE_STREAM_DECODER_SEEK_ERROR",
+	"FLAC__SEEKABLE_STREAM_DECODER_ALREADY_INITIALIZED",
+	"FLAC__SEEKABLE_STREAM_DECODER_INVALID_CALLBACK",
+	"FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED"
+};
+
+FLAC_API const char * const FLAC__SeekableStreamDecoderReadStatusString[] = {
+	"FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK",
+	"FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_ERROR"
+};
+
+FLAC_API const char * const FLAC__SeekableStreamDecoderSeekStatusString[] = {
+	"FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK",
+	"FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR"
+};
+
+FLAC_API const char * const FLAC__SeekableStreamDecoderTellStatusString[] = {
+	"FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK",
+	"FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_ERROR"
+};
+
+FLAC_API const char * const FLAC__SeekableStreamDecoderLengthStatusString[] = {
+	"FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK",
+	"FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_ERROR"
+};
+
+
+/***********************************************************************
+ *
+ * Class constructor/destructor
+ *
+ ***********************************************************************/
+
+FLAC_API FLAC__SeekableStreamDecoder *FLAC__seekable_stream_decoder_new()
+{
+	FLAC__SeekableStreamDecoder *decoder;
+
+	FLAC__ASSERT(sizeof(int) >= 4); /* we want to die right away if this is not true */
+
+	decoder = (FLAC__SeekableStreamDecoder*)calloc(1, sizeof(FLAC__SeekableStreamDecoder));
+	if(decoder == 0) {
+		return 0;
+	}
+
+	decoder->protected_ = (FLAC__SeekableStreamDecoderProtected*)calloc(1, sizeof(FLAC__SeekableStreamDecoderProtected));
+	if(decoder->protected_ == 0) {
+		free(decoder);
+		return 0;
+	}
+
+	decoder->private_ = (FLAC__SeekableStreamDecoderPrivate*)calloc(1, sizeof(FLAC__SeekableStreamDecoderPrivate));
+	if(decoder->private_ == 0) {
+		free(decoder->protected_);
+		free(decoder);
+		return 0;
+	}
+
+	decoder->private_->stream_decoder = FLAC__stream_decoder_new();
+	if(0 == decoder->private_->stream_decoder) {
+		free(decoder->private_);
+		free(decoder->protected_);
+		free(decoder);
+		return 0;
+	}
+
+	set_defaults_(decoder);
+
+	decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED;
+
+	return decoder;
+}
+
+FLAC_API void FLAC__seekable_stream_decoder_delete(FLAC__SeekableStreamDecoder *decoder)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->protected_);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->private_->stream_decoder);
+
+	(void)FLAC__seekable_stream_decoder_finish(decoder);
+
+	FLAC__stream_decoder_delete(decoder->private_->stream_decoder);
+
+	free(decoder->private_);
+	free(decoder->protected_);
+	free(decoder);
+}
+
+/***********************************************************************
+ *
+ * Public class methods
+ *
+ ***********************************************************************/
+
+FLAC_API FLAC__SeekableStreamDecoderState FLAC__seekable_stream_decoder_init(FLAC__SeekableStreamDecoder *decoder)
+{
+	FLAC__ASSERT(0 != decoder);
+
+	if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED)
+		return decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_ALREADY_INITIALIZED;
+
+	if(0 == decoder->private_->read_callback || 0 == decoder->private_->seek_callback || 0 == decoder->private_->tell_callback || 0 == decoder->private_->length_callback || 0 == decoder->private_->eof_callback)
+		return decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_INVALID_CALLBACK;
+
+	if(0 == decoder->private_->write_callback || 0 == decoder->private_->metadata_callback || 0 == decoder->private_->error_callback)
+		return decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_INVALID_CALLBACK;
+
+	decoder->private_->seek_table = 0;
+
+	decoder->private_->do_md5_checking = decoder->protected_->md5_checking;
+
+	/* We initialize the FLAC__MD5Context even though we may never use it.  This
+	 * is because md5 checking may be turned on to start and then turned off if
+	 * a seek occurs.  So we always init the context here and finalize it in
+	 * FLAC__seekable_stream_decoder_finish() to make sure things are always
+	 * cleaned up properly.
+	 */
+	FLAC__MD5Init(&decoder->private_->md5context);
+
+	FLAC__stream_decoder_set_read_callback(decoder->private_->stream_decoder, read_callback_);
+	FLAC__stream_decoder_set_write_callback(decoder->private_->stream_decoder, write_callback_);
+	FLAC__stream_decoder_set_metadata_callback(decoder->private_->stream_decoder, metadata_callback_);
+	FLAC__stream_decoder_set_error_callback(decoder->private_->stream_decoder, error_callback_);
+	FLAC__stream_decoder_set_client_data(decoder->private_->stream_decoder, decoder);
+
+	/* We always want to see these blocks.  Whether or not we pass them up
+	 * through the metadata callback will be determined by flags set in our
+	 * implementation of ..._set_metadata_respond/ignore...()
+	 */
+	FLAC__stream_decoder_set_metadata_respond(decoder->private_->stream_decoder, FLAC__METADATA_TYPE_STREAMINFO);
+	FLAC__stream_decoder_set_metadata_respond(decoder->private_->stream_decoder, FLAC__METADATA_TYPE_SEEKTABLE);
+
+	if(FLAC__stream_decoder_init(decoder->private_->stream_decoder) != FLAC__STREAM_DECODER_SEARCH_FOR_METADATA)
+		return decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR;
+
+	return decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_OK;
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_decoder_finish(FLAC__SeekableStreamDecoder *decoder)
+{
+	FLAC__bool md5_failed = false;
+
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->protected_);
+
+	if(decoder->protected_->state == FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED)
+		return true;
+
+	FLAC__ASSERT(0 != decoder->private_->stream_decoder);
+
+	/* see the comment in FLAC__seekable_stream_decoder_init() as to why we
+	 * always call FLAC__MD5Final()
+	 */
+	FLAC__MD5Final(decoder->private_->computed_md5sum, &decoder->private_->md5context);
+
+	FLAC__stream_decoder_finish(decoder->private_->stream_decoder);
+
+	if(decoder->private_->do_md5_checking) {
+		if(memcmp(decoder->private_->stored_md5sum, decoder->private_->computed_md5sum, 16))
+			md5_failed = true;
+	}
+
+	set_defaults_(decoder);
+
+	decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED;
+
+	return !md5_failed;
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_md5_checking(FLAC__SeekableStreamDecoder *decoder, FLAC__bool value)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->protected_);
+	if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED)
+		return false;
+	decoder->protected_->md5_checking = value;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_read_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderReadCallback value)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->protected_);
+	if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED)
+		return false;
+	decoder->private_->read_callback = value;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_seek_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderSeekCallback value)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->protected_);
+	if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED)
+		return false;
+	decoder->private_->seek_callback = value;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_tell_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderTellCallback value)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->protected_);
+	if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED)
+		return false;
+	decoder->private_->tell_callback = value;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_length_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderLengthCallback value)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->protected_);
+	if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED)
+		return false;
+	decoder->private_->length_callback = value;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_eof_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderEofCallback value)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->protected_);
+	if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED)
+		return false;
+	decoder->private_->eof_callback = value;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_write_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderWriteCallback value)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->protected_);
+	if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED)
+		return false;
+	decoder->private_->write_callback = value;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_metadata_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderMetadataCallback value)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->protected_);
+	if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED)
+		return false;
+	decoder->private_->metadata_callback = value;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_error_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderErrorCallback value)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->protected_);
+	if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED)
+		return false;
+	decoder->private_->error_callback = value;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_client_data(FLAC__SeekableStreamDecoder *decoder, void *value)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->protected_);
+	if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED)
+		return false;
+	decoder->private_->client_data = value;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_metadata_respond(FLAC__SeekableStreamDecoder *decoder, FLAC__MetadataType type)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->protected_);
+	FLAC__ASSERT(0 != decoder->private_->stream_decoder);
+	if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED)
+		return false;
+	if(type == FLAC__METADATA_TYPE_STREAMINFO)
+		decoder->private_->ignore_stream_info_block = false;
+	else if(type == FLAC__METADATA_TYPE_SEEKTABLE)
+		decoder->private_->ignore_seek_table_block = false;
+	return FLAC__stream_decoder_set_metadata_respond(decoder->private_->stream_decoder, type);
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_metadata_respond_application(FLAC__SeekableStreamDecoder *decoder, const FLAC__byte id[4])
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->protected_);
+	FLAC__ASSERT(0 != decoder->private_->stream_decoder);
+	if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED)
+		return false;
+	return FLAC__stream_decoder_set_metadata_respond_application(decoder->private_->stream_decoder, id);
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_metadata_respond_all(FLAC__SeekableStreamDecoder *decoder)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->protected_);
+	FLAC__ASSERT(0 != decoder->private_->stream_decoder);
+	if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED)
+		return false;
+	decoder->private_->ignore_stream_info_block = false;
+	decoder->private_->ignore_seek_table_block = false;
+	return FLAC__stream_decoder_set_metadata_respond_all(decoder->private_->stream_decoder);
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_metadata_ignore(FLAC__SeekableStreamDecoder *decoder, FLAC__MetadataType type)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->protected_);
+	FLAC__ASSERT(0 != decoder->private_->stream_decoder);
+	if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED)
+		return false;
+	if(type == FLAC__METADATA_TYPE_STREAMINFO) {
+		decoder->private_->ignore_stream_info_block = true;
+		return true;
+	}
+	else if(type == FLAC__METADATA_TYPE_SEEKTABLE) {
+		decoder->private_->ignore_seek_table_block = true;
+		return true;
+	}
+	else
+		return FLAC__stream_decoder_set_metadata_ignore(decoder->private_->stream_decoder, type);
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_metadata_ignore_application(FLAC__SeekableStreamDecoder *decoder, const FLAC__byte id[4])
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->protected_);
+	FLAC__ASSERT(0 != decoder->private_->stream_decoder);
+	if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED)
+		return false;
+	return FLAC__stream_decoder_set_metadata_ignore_application(decoder->private_->stream_decoder, id);
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_decoder_set_metadata_ignore_all(FLAC__SeekableStreamDecoder *decoder)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->protected_);
+	FLAC__ASSERT(0 != decoder->private_->stream_decoder);
+	if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED)
+		return false;
+	decoder->private_->ignore_stream_info_block = true;
+	decoder->private_->ignore_seek_table_block = true;
+	return
+		FLAC__stream_decoder_set_metadata_ignore_all(decoder->private_->stream_decoder) &&
+		FLAC__stream_decoder_set_metadata_respond(decoder->private_->stream_decoder, FLAC__METADATA_TYPE_STREAMINFO) &&
+		FLAC__stream_decoder_set_metadata_respond(decoder->private_->stream_decoder, FLAC__METADATA_TYPE_SEEKTABLE);
+}
+
+FLAC_API FLAC__SeekableStreamDecoderState FLAC__seekable_stream_decoder_get_state(const FLAC__SeekableStreamDecoder *decoder)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->protected_);
+	return decoder->protected_->state;
+}
+
+FLAC_API FLAC__StreamDecoderState FLAC__seekable_stream_decoder_get_stream_decoder_state(const FLAC__SeekableStreamDecoder *decoder)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	return FLAC__stream_decoder_get_state(decoder->private_->stream_decoder);
+}
+
+FLAC_API const char *FLAC__seekable_stream_decoder_get_resolved_state_string(const FLAC__SeekableStreamDecoder *decoder)
+{
+	if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR)
+		return FLAC__SeekableStreamDecoderStateString[decoder->protected_->state];
+	else
+		return FLAC__stream_decoder_get_resolved_state_string(decoder->private_->stream_decoder);
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_decoder_get_md5_checking(const FLAC__SeekableStreamDecoder *decoder)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->protected_);
+	return decoder->protected_->md5_checking;
+}
+
+FLAC_API unsigned FLAC__seekable_stream_decoder_get_channels(const FLAC__SeekableStreamDecoder *decoder)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	return FLAC__stream_decoder_get_channels(decoder->private_->stream_decoder);
+}
+
+FLAC_API FLAC__ChannelAssignment FLAC__seekable_stream_decoder_get_channel_assignment(const FLAC__SeekableStreamDecoder *decoder)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	return FLAC__stream_decoder_get_channel_assignment(decoder->private_->stream_decoder);
+}
+
+FLAC_API unsigned FLAC__seekable_stream_decoder_get_bits_per_sample(const FLAC__SeekableStreamDecoder *decoder)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	return FLAC__stream_decoder_get_bits_per_sample(decoder->private_->stream_decoder);
+}
+
+FLAC_API unsigned FLAC__seekable_stream_decoder_get_sample_rate(const FLAC__SeekableStreamDecoder *decoder)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	return FLAC__stream_decoder_get_sample_rate(decoder->private_->stream_decoder);
+}
+
+FLAC_API unsigned FLAC__seekable_stream_decoder_get_blocksize(const FLAC__SeekableStreamDecoder *decoder)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	return FLAC__stream_decoder_get_blocksize(decoder->private_->stream_decoder);
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_decoder_get_decode_position(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *position)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != position);
+
+	if(decoder->private_->tell_callback(decoder, position, decoder->private_->client_data) != FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK)
+		return false;
+	FLAC__ASSERT(*position >= FLAC__stream_decoder_get_input_bytes_unconsumed(decoder->private_->stream_decoder));
+	*position -= FLAC__stream_decoder_get_input_bytes_unconsumed(decoder->private_->stream_decoder);
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_decoder_flush(FLAC__SeekableStreamDecoder *decoder)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->protected_);
+
+	decoder->private_->do_md5_checking = false;
+
+	if(!FLAC__stream_decoder_flush(decoder->private_->stream_decoder)) {
+		decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR;
+		return false;
+	}
+
+	decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_OK;
+
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_decoder_reset(FLAC__SeekableStreamDecoder *decoder)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->protected_);
+
+	if(!FLAC__seekable_stream_decoder_flush(decoder)) {
+		decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR;
+		return false;
+	}
+
+	if(!FLAC__stream_decoder_reset(decoder->private_->stream_decoder)) {
+		decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR;
+		return false;
+	}
+
+	decoder->private_->seek_table = 0;
+
+	decoder->private_->do_md5_checking = decoder->protected_->md5_checking;
+
+	/* We initialize the FLAC__MD5Context even though we may never use it.  This
+	 * is because md5 checking may be turned on to start and then turned off if
+	 * a seek occurs.  So we always init the context here and finalize it in
+	 * FLAC__seekable_stream_decoder_finish() to make sure things are always
+	 * cleaned up properly.
+	 */
+	FLAC__MD5Init(&decoder->private_->md5context);
+
+	decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_OK;
+
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_decoder_process_single(FLAC__SeekableStreamDecoder *decoder)
+{
+	FLAC__bool ret;
+	FLAC__ASSERT(0 != decoder);
+
+	if(decoder->private_->stream_decoder->protected_->state == FLAC__STREAM_DECODER_END_OF_STREAM)
+		decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM;
+
+	if(decoder->protected_->state == FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM)
+		return true;
+
+	FLAC__ASSERT(decoder->protected_->state == FLAC__SEEKABLE_STREAM_DECODER_OK);
+
+	ret = FLAC__stream_decoder_process_single(decoder->private_->stream_decoder);
+	if(!ret)
+		decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR;
+
+	return ret;
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_decoder_process_until_end_of_metadata(FLAC__SeekableStreamDecoder *decoder)
+{
+	FLAC__bool ret;
+	FLAC__ASSERT(0 != decoder);
+
+	if(decoder->private_->stream_decoder->protected_->state == FLAC__STREAM_DECODER_END_OF_STREAM)
+		decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM;
+
+	if(decoder->protected_->state == FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM)
+		return true;
+
+	FLAC__ASSERT(decoder->protected_->state == FLAC__SEEKABLE_STREAM_DECODER_OK);
+
+	ret = FLAC__stream_decoder_process_until_end_of_metadata(decoder->private_->stream_decoder);
+	if(!ret)
+		decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR;
+
+	return ret;
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_decoder_process_until_end_of_stream(FLAC__SeekableStreamDecoder *decoder)
+{
+	FLAC__bool ret;
+	FLAC__ASSERT(0 != decoder);
+
+	if(decoder->private_->stream_decoder->protected_->state == FLAC__STREAM_DECODER_END_OF_STREAM)
+		decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM;
+
+	if(decoder->protected_->state == FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM)
+		return true;
+
+	FLAC__ASSERT(decoder->protected_->state == FLAC__SEEKABLE_STREAM_DECODER_OK);
+
+	ret = FLAC__stream_decoder_process_until_end_of_stream(decoder->private_->stream_decoder);
+	if(!ret)
+		decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR;
+
+	return ret;
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_decoder_skip_single_frame(FLAC__SeekableStreamDecoder *decoder)
+{
+	FLAC__bool ret;
+	FLAC__ASSERT(0 != decoder);
+
+	if(decoder->private_->stream_decoder->protected_->state == FLAC__STREAM_DECODER_END_OF_STREAM)
+		decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM;
+
+	if(decoder->protected_->state == FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM)
+		return true;
+
+	FLAC__ASSERT(decoder->protected_->state == FLAC__SEEKABLE_STREAM_DECODER_OK);
+
+	ret = FLAC__stream_decoder_skip_single_frame(decoder->private_->stream_decoder);
+	if(!ret)
+		decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR;
+
+	return ret;
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_decoder_seek_absolute(FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 sample)
+{
+	FLAC__uint64 length;
+
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(decoder->protected_->state == FLAC__SEEKABLE_STREAM_DECODER_OK || decoder->protected_->state == FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM);
+
+	decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_SEEKING;
+
+	/* turn off md5 checking if a seek is attempted */
+	decoder->private_->do_md5_checking = false;
+
+	if(!FLAC__stream_decoder_reset(decoder->private_->stream_decoder)) {
+		decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR;
+		return false;
+	}
+	/* get the file length */
+	if(decoder->private_->length_callback(decoder, &length, decoder->private_->client_data) != FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK) {
+		decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_SEEK_ERROR;
+		return false;
+	}
+	/* rewind */
+	if(decoder->private_->seek_callback(decoder, 0, decoder->private_->client_data) != FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK) {
+		decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_SEEK_ERROR;
+		return false;
+	}
+	if(!FLAC__stream_decoder_process_until_end_of_metadata(decoder->private_->stream_decoder)) {
+		decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR;
+		return false;
+	}
+	if(decoder->private_->stream_info.total_samples > 0 && sample >= decoder->private_->stream_info.total_samples) {
+		decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_SEEK_ERROR;
+		return false;
+	}
+
+	return seek_to_absolute_sample_(decoder, length, sample);
+}
+
+/***********************************************************************
+ *
+ * Private class methods
+ *
+ ***********************************************************************/
+
+void set_defaults_(FLAC__SeekableStreamDecoder *decoder)
+{
+	decoder->private_->read_callback = 0;
+	decoder->private_->seek_callback = 0;
+	decoder->private_->tell_callback = 0;
+	decoder->private_->length_callback = 0;
+	decoder->private_->eof_callback = 0;
+	decoder->private_->write_callback = 0;
+	decoder->private_->metadata_callback = 0;
+	decoder->private_->error_callback = 0;
+	decoder->private_->client_data = 0;
+	/* WATCHOUT: these should match the default behavior of FLAC__StreamDecoder */
+	decoder->private_->ignore_stream_info_block = false;
+	decoder->private_->ignore_seek_table_block = true;
+
+	decoder->protected_->md5_checking = false;
+}
+
+FLAC__StreamDecoderReadStatus read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data)
+{
+	FLAC__SeekableStreamDecoder *seekable_stream_decoder = (FLAC__SeekableStreamDecoder *)client_data;
+	(void)decoder;
+	if(seekable_stream_decoder->private_->eof_callback(seekable_stream_decoder, seekable_stream_decoder->private_->client_data)) {
+		*bytes = 0;
+#if 0
+@@@@@@ verify that this is not needed
+		seekable_stream_decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM;
+#endif
+		return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+	}
+	else if(*bytes > 0) {
+		if(seekable_stream_decoder->private_->read_callback(seekable_stream_decoder, buffer, bytes, seekable_stream_decoder->private_->client_data) != FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK) {
+			seekable_stream_decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_READ_ERROR;
+			return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+		}
+		if(*bytes == 0) {
+			if(seekable_stream_decoder->private_->eof_callback(seekable_stream_decoder, seekable_stream_decoder->private_->client_data)) {
+#if 0
+@@@@@@ verify that this is not needed
+				seekable_stream_decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM;
+#endif
+				return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+			}
+			else
+				return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+		}
+		else {
+			return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+		}
+	}
+	else
+		return FLAC__STREAM_DECODER_READ_STATUS_ABORT; /* abort to avoid a deadlock */
+}
+
+FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
+{
+	FLAC__SeekableStreamDecoder *seekable_stream_decoder = (FLAC__SeekableStreamDecoder *)client_data;
+	(void)decoder;
+
+	if(seekable_stream_decoder->protected_->state == FLAC__SEEKABLE_STREAM_DECODER_SEEKING) {
+		FLAC__uint64 this_frame_sample = frame->header.number.sample_number;
+		FLAC__uint64 next_frame_sample = this_frame_sample + (FLAC__uint64)frame->header.blocksize;
+		FLAC__uint64 target_sample = seekable_stream_decoder->private_->target_sample;
+
+		FLAC__ASSERT(frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER);
+
+		seekable_stream_decoder->private_->last_frame = *frame; /* save the frame */
+		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 */
+			seekable_stream_decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_OK;
+			/* shift out the samples before target_sample */
+			if(delta > 0) {
+				unsigned channel;
+				const FLAC__int32 *newbuffer[FLAC__MAX_CHANNELS];
+				for(channel = 0; channel < frame->header.channels; channel++)
+					newbuffer[channel] = buffer[channel] + delta;
+				seekable_stream_decoder->private_->last_frame.header.blocksize -= delta;
+				seekable_stream_decoder->private_->last_frame.header.number.sample_number += (FLAC__uint64)delta;
+				/* write the relevant samples */
+				return seekable_stream_decoder->private_->write_callback(seekable_stream_decoder, &seekable_stream_decoder->private_->last_frame, newbuffer, seekable_stream_decoder->private_->client_data);
+			}
+			else {
+				/* write the relevant samples */
+				return seekable_stream_decoder->private_->write_callback(seekable_stream_decoder, frame, buffer, seekable_stream_decoder->private_->client_data);
+			}
+		}
+		else {
+			return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+		}
+	}
+	else {
+		if(seekable_stream_decoder->private_->do_md5_checking) {
+			if(!FLAC__MD5Accumulate(&seekable_stream_decoder->private_->md5context, buffer, frame->header.channels, frame->header.blocksize, (frame->header.bits_per_sample+7) / 8))
+				return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+		}
+		return seekable_stream_decoder->private_->write_callback(seekable_stream_decoder, frame, buffer, seekable_stream_decoder->private_->client_data);
+	}
+}
+
+void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
+{
+	FLAC__SeekableStreamDecoder *seekable_stream_decoder = (FLAC__SeekableStreamDecoder *)client_data;
+	(void)decoder;
+
+	if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
+		seekable_stream_decoder->private_->stream_info = metadata->data.stream_info;
+		/* save the MD5 signature for comparison later */
+		memcpy(seekable_stream_decoder->private_->stored_md5sum, metadata->data.stream_info.md5sum, 16);
+		if(0 == memcmp(seekable_stream_decoder->private_->stored_md5sum, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16))
+			seekable_stream_decoder->private_->do_md5_checking = false;
+	}
+	else if(metadata->type == FLAC__METADATA_TYPE_SEEKTABLE) {
+		seekable_stream_decoder->private_->seek_table = &metadata->data.seek_table;
+	}
+
+	if(seekable_stream_decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_SEEKING) {
+		FLAC__bool ignore_block = false;
+		if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO && seekable_stream_decoder->private_->ignore_stream_info_block)
+			ignore_block = true;
+		else if(metadata->type == FLAC__METADATA_TYPE_SEEKTABLE && seekable_stream_decoder->private_->ignore_seek_table_block)
+			ignore_block = true;
+		if(!ignore_block)
+			seekable_stream_decoder->private_->metadata_callback(seekable_stream_decoder, metadata, seekable_stream_decoder->private_->client_data);
+	}
+}
+
+void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+	FLAC__SeekableStreamDecoder *seekable_stream_decoder = (FLAC__SeekableStreamDecoder *)client_data;
+	(void)decoder;
+
+	if(seekable_stream_decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_SEEKING)
+		seekable_stream_decoder->private_->error_callback(seekable_stream_decoder, status, seekable_stream_decoder->private_->client_data);
+}
+
+FLAC__bool seek_to_absolute_sample_(FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 stream_length, FLAC__uint64 target_sample)
+{
+	FLAC__uint64 first_frame_offset, lower_bound, upper_bound;
+	FLAC__int64 pos = -1, last_pos = -1;
+	int i, lower_seek_point = -1, upper_seek_point = -1;
+	unsigned approx_bytes_per_frame;
+	FLAC__uint64 last_frame_sample = FLAC__U64L(0xffffffffffffffff);
+	FLAC__bool needs_seek;
+	const FLAC__uint64 total_samples = decoder->private_->stream_info.total_samples;
+	const unsigned min_blocksize = decoder->private_->stream_info.min_blocksize;
+	const unsigned max_blocksize = decoder->private_->stream_info.max_blocksize;
+	const unsigned max_framesize = decoder->private_->stream_info.max_framesize;
+	const unsigned channels = FLAC__seekable_stream_decoder_get_channels(decoder);
+	const unsigned bps = FLAC__seekable_stream_decoder_get_bits_per_sample(decoder);
+
+	/* we are just guessing here, but we want to guess high, not low */
+	if(max_framesize > 0) {
+		approx_bytes_per_frame = max_framesize;
+	}
+	/*
+	 * Check if it's a known fixed-blocksize stream.  Note that though
+	 * the spec doesn't allow zeroes in the STREAMINFO block, we may
+	 * never get a STREAMINFO block when decoding so the value of
+	 * min_blocksize might be zero.
+	 */
+	else if(min_blocksize == max_blocksize && min_blocksize > 0) {
+		/* note there are no () around 'bps/8' to keep precision up since it's an integer calulation */
+		approx_bytes_per_frame = min_blocksize * channels * bps/8 + 64;
+	}
+	else
+		approx_bytes_per_frame = 4608 * channels * bps/8 + 64;
+
+	/*
+	 * The decode position is currently at the first frame since we
+	 * rewound and processed metadata.
+	 */
+	if(!FLAC__seekable_stream_decoder_get_decode_position(decoder, &first_frame_offset)) {
+		decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_SEEK_ERROR;
+		return false;
+	}
+
+	/*
+	 * First, we set an upper and lower bound on where in the
+	 * stream we will search.  For now we assume the worst case
+	 * scenario, which is our best guess at the beginning of
+	 * the first and last frames.
+	 */
+	lower_bound = first_frame_offset;
+
+	/* calc the upper_bound, beyond which we never want to seek */
+	if(max_framesize > 0)
+		upper_bound = stream_length - (max_framesize + 128 + 2); /* 128 for a possible ID3V1 tag, 2 for indexing differences */
+	else
+		upper_bound = stream_length - ((channels * bps * FLAC__MAX_BLOCK_SIZE) / 8 + 128 + 2);
+
+	/*
+	 * Now we refine the bounds if we have a seektable with
+	 * suitable points.  Note that according to the spec they
+	 * must be ordered by ascending sample number.
+	 */
+	if(0 != decoder->private_->seek_table) {
+		/* find the closest seek point <= target_sample, if it exists */
+		for(i = (int)decoder->private_->seek_table->num_points - 1; i >= 0; i--) {
+			if(decoder->private_->seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER && decoder->private_->seek_table->points[i].sample_number <= target_sample)
+				break;
+		}
+		if(i >= 0) { /* i.e. we found a suitable seek point... */
+			lower_bound = first_frame_offset + decoder->private_->seek_table->points[i].stream_offset;
+			lower_seek_point = i;
+		}
+
+		/* find the closest seek point > target_sample, if it exists */
+		for(i = 0; i < (int)decoder->private_->seek_table->num_points; i++) {
+			if(decoder->private_->seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER && decoder->private_->seek_table->points[i].sample_number > target_sample)
+				break;
+		}
+		if(i < (int)decoder->private_->seek_table->num_points) { /* i.e. we found a suitable seek point... */
+			upper_bound = first_frame_offset + decoder->private_->seek_table->points[i].stream_offset;
+			upper_seek_point = i;
+		}
+	}
+
+	/*
+	 * Now guess at where within those bounds our target
+	 * sample will be.
+	 */
+	if(lower_seek_point >= 0) {
+		/* first see if our sample is within a few frames of the lower seekpoint */
+		if(decoder->private_->seek_table->points[lower_seek_point].sample_number <= target_sample && target_sample < decoder->private_->seek_table->points[lower_seek_point].sample_number + (decoder->private_->seek_table->points[lower_seek_point].frame_samples * 4)) {
+			pos = (FLAC__int64)lower_bound;
+		}
+		else if(upper_seek_point >= 0) {
+			const FLAC__uint64 target_offset = target_sample - decoder->private_->seek_table->points[lower_seek_point].sample_number;
+			const FLAC__uint64 range_samples = decoder->private_->seek_table->points[upper_seek_point].sample_number - decoder->private_->seek_table->points[lower_seek_point].sample_number;
+			const FLAC__uint64 range_bytes = upper_bound - lower_bound;
+#if defined _MSC_VER || defined __MINGW32__
+			/* with VC++ you have to spoon feed it the casting */
+			pos = (FLAC__int64)lower_bound + (FLAC__int64)((double)(FLAC__int64)target_offset / (double)(FLAC__int64)range_samples * (double)(FLAC__int64)(range_bytes-1)) - approx_bytes_per_frame;
+#else
+			pos = (FLAC__int64)lower_bound + (FLAC__int64)((double)target_offset / (double)range_samples * (double)(range_bytes-1)) - approx_bytes_per_frame;
+#endif
+		}
+	}
+
+	/*
+	 * If there's no seek table, we need to use the metadata (if we
+	 * have it) and the filelength to estimate the position of the
+	 * frame with the correct sample.
+	 */
+	if(pos < 0 && total_samples > 0) {
+#if defined _MSC_VER || defined __MINGW32__
+		/* with VC++ you have to spoon feed it the casting */
+		pos = (FLAC__int64)first_frame_offset + (FLAC__int64)((double)(FLAC__int64)target_sample / (double)(FLAC__int64)total_samples * (double)(FLAC__int64)(stream_length-first_frame_offset-1)) - approx_bytes_per_frame;
+#else
+		pos = (FLAC__int64)first_frame_offset + (FLAC__int64)((double)target_sample / (double)total_samples * (double)(stream_length-first_frame_offset-1)) - approx_bytes_per_frame;
+#endif
+	}
+
+	/*
+	 * If there's no seek table and total_samples is unknown, we
+	 * don't even bother trying to figure out a target, we just use
+	 * our current position.
+	 */
+	if(pos < 0) {
+		FLAC__uint64 upos;
+		if(decoder->private_->tell_callback(decoder, &upos, decoder->private_->client_data) != FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK) {
+			decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_SEEK_ERROR;
+			return false;
+		}
+		pos = (FLAC__int64)upos;
+		needs_seek = false;
+	}
+	else
+		needs_seek = true;
+
+	/* clip the position to the bounds, lower bound takes precedence */
+	if(pos >= (FLAC__int64)upper_bound) {
+		pos = (FLAC__int64)upper_bound-1;
+		needs_seek = true;
+	}
+	if(pos < (FLAC__int64)lower_bound) {
+		pos = (FLAC__int64)lower_bound;
+		needs_seek = true;
+	}
+
+	decoder->private_->target_sample = target_sample;
+	while(1) {
+		if(needs_seek) {
+			if(decoder->private_->seek_callback(decoder, (FLAC__uint64)pos, decoder->private_->client_data) != FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK) {
+				decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_SEEK_ERROR;
+				return false;
+			}
+			if(!FLAC__stream_decoder_flush(decoder->private_->stream_decoder)) {
+				decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR;
+				return false;
+			}
+		}
+		/* Now we need to get a frame.  It is possible for our seek
+		 * to land in the middle of audio data that looks exactly like
+		 * a frame header from a future version of an encoder.  When
+		 * that happens, FLAC__stream_decoder_process_single() will
+		 * return false and the state will be
+		 * FLAC__STREAM_DECODER_UNPARSEABLE_STREAM.  But there is a
+		 * remote possibility that it is properly synced at such a
+		 * "future-codec frame", so to make sure, we wait to see
+		 * several "unparseable" errors in a row before bailing out.
+		 */
+		{
+			unsigned unparseable_count;
+			FLAC__bool got_a_frame = false;
+			for (unparseable_count = 0; !got_a_frame && unparseable_count < 10; unparseable_count++) {
+				if(FLAC__stream_decoder_process_single(decoder->private_->stream_decoder))
+					got_a_frame = true;
+				else if(decoder->private_->stream_decoder->protected_->state == FLAC__STREAM_DECODER_UNPARSEABLE_STREAM)
+					/* try again.  we don't want to flush the decoder since that clears the bitbuffer */
+					decoder->private_->stream_decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+				else /* it's a real error */
+					break;
+			}
+			if (!got_a_frame) {
+				decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_SEEK_ERROR;
+				return false;
+			}
+		}
+		/* our write callback will change the state when it gets to the target frame */
+		if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_SEEKING) {
+			break;
+		}
+		else { /* we need to narrow the search */
+			const FLAC__uint64 this_frame_sample = decoder->private_->last_frame.header.number.sample_number;
+			FLAC__ASSERT(decoder->private_->last_frame.header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER);
+			if(this_frame_sample == last_frame_sample && pos < last_pos) {
+				/* our last move backwards wasn't big enough, double it */
+				pos -= (last_pos - pos);
+				needs_seek = true;
+			}
+			else {
+				if(target_sample < this_frame_sample) {
+					last_pos = pos;
+					approx_bytes_per_frame = decoder->private_->last_frame.header.blocksize * channels * bps/8 + 64;
+					pos -= approx_bytes_per_frame;
+					needs_seek = true;
+				}
+				else { /* target_sample >= this_frame_sample + this frame's blocksize */
+					FLAC__uint64 upos;
+					if(decoder->private_->tell_callback(decoder, &upos, decoder->private_->client_data) != FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK) {
+						decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_SEEK_ERROR;
+						return false;
+					}
+					last_pos = pos;
+					pos = (FLAC__int64)upos;
+					pos -= FLAC__stream_decoder_get_input_bytes_unconsumed(decoder->private_->stream_decoder);
+					needs_seek = false;
+					/*
+					 * if we haven't hit the target frame yet and our position hasn't changed,
+					 * it means we're at the end of the stream and the seek target does not exist.
+					 */
+					if(last_pos == pos) {
+						decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_SEEK_ERROR;
+						return false;
+					}
+				}
+			}
+			if(pos < (FLAC__int64)lower_bound)
+				pos = (FLAC__int64)lower_bound;
+			last_frame_sample = this_frame_sample;
+		}
+	}
+
+	return true;
+}
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/seekable_stream_encoder.c
@@ -1,0 +1,943 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2002,2003,2004  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h> /* for calloc() */
+#include <string.h> /* for memcpy() */
+#include "FLAC/assert.h"
+#include "protected/seekable_stream_encoder.h"
+
+#ifdef max
+#undef max
+#endif
+#define max(a,b) ((a)>(b)?(a):(b))
+
+/***********************************************************************
+ *
+ * Private class method prototypes
+ *
+ ***********************************************************************/
+
+/* unpublished debug routines */
+extern FLAC__bool FLAC__stream_encoder_disable_constant_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value);
+extern FLAC__bool FLAC__stream_encoder_disable_fixed_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value);
+extern FLAC__bool FLAC__stream_encoder_disable_verbatim_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value);
+
+static void set_defaults_(FLAC__SeekableStreamEncoder *encoder);
+static FLAC__StreamEncoderWriteStatus write_callback_(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data);
+static void metadata_callback_(const FLAC__StreamEncoder *encoder, const FLAC__StreamMetadata *metadata, void *client_data);
+
+/***********************************************************************
+ *
+ * Private class data
+ *
+ ***********************************************************************/
+
+typedef struct FLAC__SeekableStreamEncoderPrivate {
+	FLAC__SeekableStreamEncoderSeekCallback seek_callback;
+	FLAC__SeekableStreamEncoderTellCallback tell_callback;
+	FLAC__SeekableStreamEncoderWriteCallback write_callback;
+	void *client_data;
+	FLAC__StreamEncoder *stream_encoder;
+	FLAC__StreamMetadata_SeekTable *seek_table;
+	/* internal vars (all the above are class settings) */
+	unsigned first_seekpoint_to_check;
+	FLAC__uint64 samples_written;
+} FLAC__SeekableStreamEncoderPrivate;
+
+/***********************************************************************
+ *
+ * Public static class data
+ *
+ ***********************************************************************/
+
+FLAC_API const char * const FLAC__SeekableStreamEncoderStateString[] = {
+	"FLAC__SEEKABLE_STREAM_ENCODER_OK",
+	"FLAC__SEEKABLE_STREAM_ENCODER_STREAM_ENCODER_ERROR",
+	"FLAC__SEEKABLE_STREAM_ENCODER_MEMORY_ALLOCATION_ERROR",
+	"FLAC__SEEKABLE_STREAM_ENCODER_WRITE_ERROR",
+	"FLAC__SEEKABLE_STREAM_ENCODER_READ_ERROR",
+	"FLAC__SEEKABLE_STREAM_ENCODER_SEEK_ERROR",
+	"FLAC__SEEKABLE_STREAM_ENCODER_TELL_ERROR",
+	"FLAC__SEEKABLE_STREAM_ENCODER_ALREADY_INITIALIZED",
+	"FLAC__SEEKABLE_STREAM_ENCODER_INVALID_CALLBACK",
+	"FLAC__SEEKABLE_STREAM_ENCODER_INVALID_SEEKTABLE",
+	"FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED"
+};
+
+FLAC_API const char * const FLAC__SeekableStreamEncoderSeekStatusString[] = {
+	"FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_OK",
+	"FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_ERROR"
+};
+
+FLAC_API const char * const FLAC__SeekableStreamEncoderTellStatusString[] = {
+	"FLAC__SEEKABLE_STREAM_ENCODER_TELL_STATUS_OK",
+	"FLAC__SEEKABLE_STREAM_ENCODER_TELL_STATUS_ERROR"
+};
+
+
+/***********************************************************************
+ *
+ * Class constructor/destructor
+ *
+ ***********************************************************************/
+
+FLAC_API FLAC__SeekableStreamEncoder *FLAC__seekable_stream_encoder_new()
+{
+	FLAC__SeekableStreamEncoder *encoder;
+
+	FLAC__ASSERT(sizeof(int) >= 4); /* we want to die right away if this is not true */
+
+	encoder = (FLAC__SeekableStreamEncoder*)calloc(1, sizeof(FLAC__SeekableStreamEncoder));
+	if(encoder == 0) {
+		return 0;
+	}
+
+	encoder->protected_ = (FLAC__SeekableStreamEncoderProtected*)calloc(1, sizeof(FLAC__SeekableStreamEncoderProtected));
+	if(encoder->protected_ == 0) {
+		free(encoder);
+		return 0;
+	}
+
+	encoder->private_ = (FLAC__SeekableStreamEncoderPrivate*)calloc(1, sizeof(FLAC__SeekableStreamEncoderPrivate));
+	if(encoder->private_ == 0) {
+		free(encoder->protected_);
+		free(encoder);
+		return 0;
+	}
+
+	encoder->private_->stream_encoder = FLAC__stream_encoder_new();
+	if(0 == encoder->private_->stream_encoder) {
+		free(encoder->private_);
+		free(encoder->protected_);
+		free(encoder);
+		return 0;
+	}
+
+	set_defaults_(encoder);
+
+	encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED;
+
+	return encoder;
+}
+
+FLAC_API void FLAC__seekable_stream_encoder_delete(FLAC__SeekableStreamEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->protected_);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->private_->stream_encoder);
+
+	(void)FLAC__seekable_stream_encoder_finish(encoder);
+
+	FLAC__stream_encoder_delete(encoder->private_->stream_encoder);
+
+	free(encoder->private_);
+	free(encoder->protected_);
+	free(encoder);
+}
+
+
+/***********************************************************************
+ *
+ * Public class methods
+ *
+ ***********************************************************************/
+
+FLAC_API FLAC__SeekableStreamEncoderState FLAC__seekable_stream_encoder_init(FLAC__SeekableStreamEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+
+	if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+		return encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_ALREADY_INITIALIZED;
+
+	if(0 == encoder->private_->seek_callback || 0 == encoder->private_->tell_callback || 0 == encoder->private_->write_callback)
+		return encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_INVALID_CALLBACK;
+
+	if(0 != encoder->private_->seek_table && !FLAC__format_seektable_is_legal(encoder->private_->seek_table))
+		return encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_INVALID_SEEKTABLE;
+
+	/*
+	 * These must be done before we init the stream encoder because that
+	 * calls the write_callback, which uses these values.
+	 */
+	encoder->private_->first_seekpoint_to_check = 0;
+	encoder->private_->samples_written = 0;
+	encoder->protected_->streaminfo_offset = 0;
+	encoder->protected_->seektable_offset = 0;
+	encoder->protected_->audio_offset = 0;
+
+	FLAC__stream_encoder_set_write_callback(encoder->private_->stream_encoder, write_callback_);
+	FLAC__stream_encoder_set_metadata_callback(encoder->private_->stream_encoder, metadata_callback_);
+	FLAC__stream_encoder_set_client_data(encoder->private_->stream_encoder, encoder);
+
+	if(FLAC__stream_encoder_init(encoder->private_->stream_encoder) != FLAC__STREAM_ENCODER_OK)
+		return encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_STREAM_ENCODER_ERROR;
+
+	/*
+	 * Initializing the stream encoder writes all the metadata, so we
+	 * save the stream offset now.
+	 */
+	if(encoder->private_->tell_callback(encoder, &encoder->protected_->audio_offset, encoder->private_->client_data) != FLAC__SEEKABLE_STREAM_ENCODER_TELL_STATUS_OK)
+		return encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_TELL_ERROR;
+
+	return encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_OK;
+}
+
+FLAC_API void FLAC__seekable_stream_encoder_finish(FLAC__SeekableStreamEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+
+	if(encoder->protected_->state == FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+		return;
+
+	FLAC__ASSERT(0 != encoder->private_->stream_encoder);
+
+	FLAC__stream_encoder_finish(encoder->private_->stream_encoder);
+
+	set_defaults_(encoder);
+
+	encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED;
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_verify(FLAC__SeekableStreamEncoder *encoder, FLAC__bool value)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	FLAC__ASSERT(0 != encoder->private_->stream_encoder);
+	if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+		return false;
+	return FLAC__stream_encoder_set_verify(encoder->private_->stream_encoder, value);
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_streamable_subset(FLAC__SeekableStreamEncoder *encoder, FLAC__bool value)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	FLAC__ASSERT(0 != encoder->private_->stream_encoder);
+	if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+		return false;
+	return FLAC__stream_encoder_set_streamable_subset(encoder->private_->stream_encoder, value);
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_do_mid_side_stereo(FLAC__SeekableStreamEncoder *encoder, FLAC__bool value)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	FLAC__ASSERT(0 != encoder->private_->stream_encoder);
+	if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+		return false;
+	return FLAC__stream_encoder_set_do_mid_side_stereo(encoder->private_->stream_encoder, value);
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_loose_mid_side_stereo(FLAC__SeekableStreamEncoder *encoder, FLAC__bool value)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	FLAC__ASSERT(0 != encoder->private_->stream_encoder);
+	if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+		return false;
+	return FLAC__stream_encoder_set_loose_mid_side_stereo(encoder->private_->stream_encoder, value);
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_channels(FLAC__SeekableStreamEncoder *encoder, unsigned value)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	FLAC__ASSERT(0 != encoder->private_->stream_encoder);
+	if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+		return false;
+	return FLAC__stream_encoder_set_channels(encoder->private_->stream_encoder, value);
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_bits_per_sample(FLAC__SeekableStreamEncoder *encoder, unsigned value)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	FLAC__ASSERT(0 != encoder->private_->stream_encoder);
+	if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+		return false;
+	return FLAC__stream_encoder_set_bits_per_sample(encoder->private_->stream_encoder, value);
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_sample_rate(FLAC__SeekableStreamEncoder *encoder, unsigned value)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	FLAC__ASSERT(0 != encoder->private_->stream_encoder);
+	if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+		return false;
+	return FLAC__stream_encoder_set_sample_rate(encoder->private_->stream_encoder, value);
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_blocksize(FLAC__SeekableStreamEncoder *encoder, unsigned value)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	FLAC__ASSERT(0 != encoder->private_->stream_encoder);
+	if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+		return false;
+	return FLAC__stream_encoder_set_blocksize(encoder->private_->stream_encoder, value);
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_max_lpc_order(FLAC__SeekableStreamEncoder *encoder, unsigned value)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	FLAC__ASSERT(0 != encoder->private_->stream_encoder);
+	if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+		return false;
+	return FLAC__stream_encoder_set_max_lpc_order(encoder->private_->stream_encoder, value);
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_qlp_coeff_precision(FLAC__SeekableStreamEncoder *encoder, unsigned value)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	FLAC__ASSERT(0 != encoder->private_->stream_encoder);
+	if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+		return false;
+	return FLAC__stream_encoder_set_qlp_coeff_precision(encoder->private_->stream_encoder, value);
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_do_qlp_coeff_prec_search(FLAC__SeekableStreamEncoder *encoder, FLAC__bool value)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	FLAC__ASSERT(0 != encoder->private_->stream_encoder);
+	if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+		return false;
+	return FLAC__stream_encoder_set_do_qlp_coeff_prec_search(encoder->private_->stream_encoder, value);
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_do_escape_coding(FLAC__SeekableStreamEncoder *encoder, FLAC__bool value)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	FLAC__ASSERT(0 != encoder->private_->stream_encoder);
+	if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+		return false;
+	return FLAC__stream_encoder_set_do_escape_coding(encoder->private_->stream_encoder, value);
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_do_exhaustive_model_search(FLAC__SeekableStreamEncoder *encoder, FLAC__bool value)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	FLAC__ASSERT(0 != encoder->private_->stream_encoder);
+	if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+		return false;
+	return FLAC__stream_encoder_set_do_exhaustive_model_search(encoder->private_->stream_encoder, value);
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_min_residual_partition_order(FLAC__SeekableStreamEncoder *encoder, unsigned value)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	FLAC__ASSERT(0 != encoder->private_->stream_encoder);
+	if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+		return false;
+	return FLAC__stream_encoder_set_min_residual_partition_order(encoder->private_->stream_encoder, value);
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_max_residual_partition_order(FLAC__SeekableStreamEncoder *encoder, unsigned value)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	FLAC__ASSERT(0 != encoder->private_->stream_encoder);
+	if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+		return false;
+	return FLAC__stream_encoder_set_max_residual_partition_order(encoder->private_->stream_encoder, value);
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_rice_parameter_search_dist(FLAC__SeekableStreamEncoder *encoder, unsigned value)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	FLAC__ASSERT(0 != encoder->private_->stream_encoder);
+	if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+		return false;
+	return FLAC__stream_encoder_set_rice_parameter_search_dist(encoder->private_->stream_encoder, value);
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_total_samples_estimate(FLAC__SeekableStreamEncoder *encoder, FLAC__uint64 value)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	FLAC__ASSERT(0 != encoder->private_->stream_encoder);
+	if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+		return false;
+	return FLAC__stream_encoder_set_total_samples_estimate(encoder->private_->stream_encoder, value);
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_metadata(FLAC__SeekableStreamEncoder *encoder, FLAC__StreamMetadata **metadata, unsigned num_blocks)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	FLAC__ASSERT(0 != encoder->private_->stream_encoder);
+	if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+		return false;
+	if(0 != metadata && num_blocks > 0) {
+		unsigned i;
+		for(i = 0; i < num_blocks; i++) {
+			if(0 != metadata[i] && metadata[i]->type == FLAC__METADATA_TYPE_SEEKTABLE) {
+				encoder->private_->seek_table = &metadata[i]->data.seek_table;
+				break; /* take only the first one */
+			}
+		}
+	}
+	return FLAC__stream_encoder_set_metadata(encoder->private_->stream_encoder, metadata, num_blocks);
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_seek_callback(FLAC__SeekableStreamEncoder *encoder, FLAC__SeekableStreamEncoderSeekCallback value)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+		return false;
+	encoder->private_->seek_callback = value;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_tell_callback(FLAC__SeekableStreamEncoder *encoder, FLAC__SeekableStreamEncoderTellCallback value)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+		return false;
+	encoder->private_->tell_callback = value;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_write_callback(FLAC__SeekableStreamEncoder *encoder, FLAC__SeekableStreamEncoderWriteCallback value)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+		return false;
+	encoder->private_->write_callback = value;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_client_data(FLAC__SeekableStreamEncoder *encoder, void *value)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+		return false;
+	encoder->private_->client_data = value;
+	return true;
+}
+
+/*
+ * These three functions are not static, but not publically exposed in
+ * include/FLAC/ either.  They are used by the test suite.
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_disable_constant_subframes(FLAC__SeekableStreamEncoder *encoder, FLAC__bool value)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+		return false;
+	return FLAC__stream_encoder_disable_constant_subframes(encoder->private_->stream_encoder, value);
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_disable_fixed_subframes(FLAC__SeekableStreamEncoder *encoder, FLAC__bool value)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+		return false;
+	return FLAC__stream_encoder_disable_fixed_subframes(encoder->private_->stream_encoder, value);
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_disable_verbatim_subframes(FLAC__SeekableStreamEncoder *encoder, FLAC__bool value)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
+		return false;
+	return FLAC__stream_encoder_disable_verbatim_subframes(encoder->private_->stream_encoder, value);
+}
+
+FLAC_API FLAC__SeekableStreamEncoderState FLAC__seekable_stream_encoder_get_state(const FLAC__SeekableStreamEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->protected_);
+	return encoder->protected_->state;
+}
+
+FLAC_API FLAC__StreamEncoderState FLAC__seekable_stream_encoder_get_stream_encoder_state(const FLAC__SeekableStreamEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	return FLAC__stream_encoder_get_state(encoder->private_->stream_encoder);
+}
+
+FLAC_API FLAC__StreamDecoderState FLAC__seekable_stream_encoder_get_verify_decoder_state(const FLAC__SeekableStreamEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	return FLAC__stream_encoder_get_verify_decoder_state(encoder->private_->stream_encoder);
+}
+
+FLAC_API const char *FLAC__seekable_stream_encoder_get_resolved_state_string(const FLAC__SeekableStreamEncoder *encoder)
+{
+	if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_STREAM_ENCODER_ERROR)
+		return FLAC__SeekableStreamEncoderStateString[encoder->protected_->state];
+	else
+		return FLAC__stream_encoder_get_resolved_state_string(encoder->private_->stream_encoder);
+}
+
+FLAC_API void FLAC__seekable_stream_encoder_get_verify_decoder_error_stats(const FLAC__SeekableStreamEncoder *encoder, FLAC__uint64 *absolute_sample, unsigned *frame_number, unsigned *channel, unsigned *sample, FLAC__int32 *expected, FLAC__int32 *got)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__stream_encoder_get_verify_decoder_error_stats(encoder->private_->stream_encoder, absolute_sample, frame_number, channel, sample, expected, got);
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_get_verify(const FLAC__SeekableStreamEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	return FLAC__stream_encoder_get_verify(encoder->private_->stream_encoder);
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_get_streamable_subset(const FLAC__SeekableStreamEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	return FLAC__stream_encoder_get_streamable_subset(encoder->private_->stream_encoder);
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_get_do_mid_side_stereo(const FLAC__SeekableStreamEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	return FLAC__stream_encoder_get_do_mid_side_stereo(encoder->private_->stream_encoder);
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_get_loose_mid_side_stereo(const FLAC__SeekableStreamEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	return FLAC__stream_encoder_get_loose_mid_side_stereo(encoder->private_->stream_encoder);
+}
+
+FLAC_API unsigned FLAC__seekable_stream_encoder_get_channels(const FLAC__SeekableStreamEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	return FLAC__stream_encoder_get_channels(encoder->private_->stream_encoder);
+}
+
+FLAC_API unsigned FLAC__seekable_stream_encoder_get_bits_per_sample(const FLAC__SeekableStreamEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	return FLAC__stream_encoder_get_bits_per_sample(encoder->private_->stream_encoder);
+}
+
+FLAC_API unsigned FLAC__seekable_stream_encoder_get_sample_rate(const FLAC__SeekableStreamEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	return FLAC__stream_encoder_get_sample_rate(encoder->private_->stream_encoder);
+}
+
+FLAC_API unsigned FLAC__seekable_stream_encoder_get_blocksize(const FLAC__SeekableStreamEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	return FLAC__stream_encoder_get_blocksize(encoder->private_->stream_encoder);
+}
+
+FLAC_API unsigned FLAC__seekable_stream_encoder_get_max_lpc_order(const FLAC__SeekableStreamEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	return FLAC__stream_encoder_get_max_lpc_order(encoder->private_->stream_encoder);
+}
+
+FLAC_API unsigned FLAC__seekable_stream_encoder_get_qlp_coeff_precision(const FLAC__SeekableStreamEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	return FLAC__stream_encoder_get_qlp_coeff_precision(encoder->private_->stream_encoder);
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_get_do_qlp_coeff_prec_search(const FLAC__SeekableStreamEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	return FLAC__stream_encoder_get_do_qlp_coeff_prec_search(encoder->private_->stream_encoder);
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_get_do_escape_coding(const FLAC__SeekableStreamEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	return FLAC__stream_encoder_get_do_escape_coding(encoder->private_->stream_encoder);
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_get_do_exhaustive_model_search(const FLAC__SeekableStreamEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	return FLAC__stream_encoder_get_do_exhaustive_model_search(encoder->private_->stream_encoder);
+}
+
+FLAC_API unsigned FLAC__seekable_stream_encoder_get_min_residual_partition_order(const FLAC__SeekableStreamEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	return FLAC__stream_encoder_get_min_residual_partition_order(encoder->private_->stream_encoder);
+}
+
+FLAC_API unsigned FLAC__seekable_stream_encoder_get_max_residual_partition_order(const FLAC__SeekableStreamEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	return FLAC__stream_encoder_get_max_residual_partition_order(encoder->private_->stream_encoder);
+}
+
+FLAC_API unsigned FLAC__seekable_stream_encoder_get_rice_parameter_search_dist(const FLAC__SeekableStreamEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	return FLAC__stream_encoder_get_rice_parameter_search_dist(encoder->private_->stream_encoder);
+}
+
+FLAC_API FLAC__uint64 FLAC__seekable_stream_encoder_get_total_samples_estimate(const FLAC__SeekableStreamEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	return FLAC__stream_encoder_get_total_samples_estimate(encoder->private_->stream_encoder);
+}
+
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_process(FLAC__SeekableStreamEncoder *encoder, const FLAC__int32 * const buffer[], unsigned samples)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	if(!FLAC__stream_encoder_process(encoder->private_->stream_encoder, buffer, samples)) {
+		encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_STREAM_ENCODER_ERROR;
+		return false;
+	}
+	else
+		return true;
+}
+
+/* 'samples' is channel-wide samples, e.g. for 1 second at 44100Hz, 'samples' = 44100 regardless of the number of channels */
+FLAC_API FLAC__bool FLAC__seekable_stream_encoder_process_interleaved(FLAC__SeekableStreamEncoder *encoder, const FLAC__int32 buffer[], unsigned samples)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	if(!FLAC__stream_encoder_process_interleaved(encoder->private_->stream_encoder, buffer, samples)) {
+		encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_STREAM_ENCODER_ERROR;
+		return false;
+	}
+	else
+		return true;
+}
+
+/***********************************************************************
+ *
+ * Private class methods
+ *
+ ***********************************************************************/
+
+void set_defaults_(FLAC__SeekableStreamEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+
+	encoder->private_->seek_callback = 0;
+	encoder->private_->tell_callback = 0;
+	encoder->private_->write_callback = 0;
+	encoder->private_->client_data = 0;
+
+	encoder->private_->seek_table = 0;
+}
+
+FLAC__StreamEncoderWriteStatus write_callback_(const FLAC__StreamEncoder *unused, const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data)
+{
+	FLAC__SeekableStreamEncoder *encoder = (FLAC__SeekableStreamEncoder*)client_data;
+	FLAC__StreamEncoderWriteStatus status;
+	FLAC__uint64 output_position;
+
+	(void)unused; /* silence compiler warning about unused parameter */
+	FLAC__ASSERT(encoder->private_->stream_encoder == unused);
+
+	if(encoder->private_->tell_callback(encoder, &output_position, encoder->private_->client_data) != FLAC__SEEKABLE_STREAM_ENCODER_TELL_STATUS_OK)
+		return encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_TELL_ERROR;
+
+	/*
+	 * Watch for the STREAMINFO block and first SEEKTABLE block to go by and store their offsets.
+	 */
+	if(samples == 0) {
+		FLAC__MetadataType type = (buffer[0] & 0x7f);
+		if(type == FLAC__METADATA_TYPE_STREAMINFO)
+			encoder->protected_->streaminfo_offset = output_position;
+		else if(type == FLAC__METADATA_TYPE_SEEKTABLE && encoder->protected_->seektable_offset == 0)
+			encoder->protected_->seektable_offset = output_position;
+	}
+
+	/*
+	 * Mark the current seek point if hit (if audio_offset == 0 that
+	 * means we're still writing metadata and haven't hit the first
+	 * frame yet)
+	 */
+	if(0 != encoder->private_->seek_table && encoder->protected_->audio_offset > 0 && encoder->private_->seek_table->num_points > 0) {
+		const unsigned blocksize = FLAC__stream_encoder_get_blocksize(encoder->private_->stream_encoder);
+		const FLAC__uint64 frame_first_sample = encoder->private_->samples_written;
+		const FLAC__uint64 frame_last_sample = frame_first_sample + (FLAC__uint64)blocksize - 1;
+		FLAC__uint64 test_sample;
+		unsigned i;
+		for(i = encoder->private_->first_seekpoint_to_check; i < encoder->private_->seek_table->num_points; i++) {
+			test_sample = encoder->private_->seek_table->points[i].sample_number;
+			if(test_sample > frame_last_sample) {
+				break;
+			}
+			else if(test_sample >= frame_first_sample) {
+				encoder->private_->seek_table->points[i].sample_number = frame_first_sample;
+				encoder->private_->seek_table->points[i].stream_offset = output_position - encoder->protected_->audio_offset;
+				encoder->private_->seek_table->points[i].frame_samples = blocksize;
+				encoder->private_->first_seekpoint_to_check++;
+				/* DO NOT: "break;" and here's why:
+				 * The seektable template may contain more than one target
+				 * sample for any given frame; we will keep looping, generating
+				 * duplicate seekpoints for them, and we'll clean it up later,
+				 * just before writing the seektable back to the metadata.
+				 */
+			}
+			else {
+				encoder->private_->first_seekpoint_to_check++;
+			}
+		}
+	}
+
+	status = encoder->private_->write_callback(encoder, buffer, bytes, samples, current_frame, encoder->private_->client_data);
+
+	if(status == FLAC__STREAM_ENCODER_WRITE_STATUS_OK) {
+		encoder->private_->samples_written += samples;
+	}
+	else
+		encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_WRITE_ERROR;
+
+	return status;
+}
+
+void metadata_callback_(const FLAC__StreamEncoder *unused, const FLAC__StreamMetadata *metadata, void *client_data)
+{
+	FLAC__SeekableStreamEncoder *encoder = (FLAC__SeekableStreamEncoder*)client_data;
+	FLAC__byte b[max(6, FLAC__STREAM_METADATA_SEEKPOINT_LENGTH)];
+	const FLAC__uint64 samples = metadata->data.stream_info.total_samples;
+	const unsigned min_framesize = metadata->data.stream_info.min_framesize;
+	const unsigned max_framesize = metadata->data.stream_info.max_framesize;
+	const unsigned bps = metadata->data.stream_info.bits_per_sample;
+
+	FLAC__ASSERT(metadata->type == FLAC__METADATA_TYPE_STREAMINFO);
+
+	/* We get called by the stream encoder when the encoding process
+	 * has finished so that we can update the STREAMINFO and SEEKTABLE
+	 * blocks.
+	 */
+
+	(void)unused; /* silence compiler warning about unused parameter */
+	FLAC__ASSERT(encoder->private_->stream_encoder == unused);
+
+	/*@@@ reopen callback here?  The docs currently require user to open files in update mode from the start */
+
+	/* 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.
+	 */
+
+	/*
+	 * Write MD5 signature
+	 */
+	{
+		const unsigned md5_offset =
+		FLAC__STREAM_METADATA_HEADER_LENGTH +
+		(
+			FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN +
+			FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN +
+			FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN +
+			FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN +
+			FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN +
+			FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN +
+			FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN +
+			FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN
+		) / 8;
+
+		if(encoder->private_->seek_callback(encoder, encoder->protected_->streaminfo_offset + md5_offset, encoder->private_->client_data) != FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_OK) {
+			encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_SEEK_ERROR;
+			return;
+		}
+		if(encoder->private_->write_callback(encoder, metadata->data.stream_info.md5sum, 16, 0, 0, encoder->private_->client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) {
+			encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_WRITE_ERROR;
+			return;
+		}
+	}
+
+	/*
+	 * Write total samples
+	 */
+	{
+		const unsigned total_samples_byte_offset =
+		FLAC__STREAM_METADATA_HEADER_LENGTH +
+		(
+			FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN +
+			FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN +
+			FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN +
+			FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN +
+			FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN +
+			FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN +
+			FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN
+			- 4
+		) / 8;
+
+		b[0] = ((FLAC__byte)(bps-1) << 4) | (FLAC__byte)((samples >> 32) & 0x0F);
+		b[1] = (FLAC__byte)((samples >> 24) & 0xFF);
+		b[2] = (FLAC__byte)((samples >> 16) & 0xFF);
+		b[3] = (FLAC__byte)((samples >> 8) & 0xFF);
+		b[4] = (FLAC__byte)(samples & 0xFF);
+		if(encoder->private_->seek_callback(encoder, encoder->protected_->streaminfo_offset + total_samples_byte_offset, encoder->private_->client_data) != FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_OK) {
+			encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_SEEK_ERROR;
+			return;
+		}
+		if(encoder->private_->write_callback(encoder, b, 5, 0, 0, encoder->private_->client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) {
+			encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_WRITE_ERROR;
+			return;
+		}
+	}
+
+	/*
+	 * Write min/max framesize
+	 */
+	{
+		const unsigned min_framesize_offset =
+		FLAC__STREAM_METADATA_HEADER_LENGTH +
+		(
+			FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN +
+			FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN
+		) / 8;
+
+		b[0] = (FLAC__byte)((min_framesize >> 16) & 0xFF);
+		b[1] = (FLAC__byte)((min_framesize >> 8) & 0xFF);
+		b[2] = (FLAC__byte)(min_framesize & 0xFF);
+		b[3] = (FLAC__byte)((max_framesize >> 16) & 0xFF);
+		b[4] = (FLAC__byte)((max_framesize >> 8) & 0xFF);
+		b[5] = (FLAC__byte)(max_framesize & 0xFF);
+		if(encoder->private_->seek_callback(encoder, encoder->protected_->streaminfo_offset + min_framesize_offset, encoder->private_->client_data) != FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_OK) {
+			encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_SEEK_ERROR;
+			return;
+		}
+		if(encoder->private_->write_callback(encoder, b, 6, 0, 0, encoder->private_->client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) {
+			encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_WRITE_ERROR;
+			return;
+		}
+	}
+
+	/*
+	 * Write seektable
+	 */
+	if(0 != encoder->private_->seek_table && encoder->private_->seek_table->num_points > 0 && encoder->protected_->seektable_offset > 0) {
+		unsigned i;
+
+		FLAC__format_seektable_sort(encoder->private_->seek_table);
+
+		FLAC__ASSERT(FLAC__format_seektable_is_legal(encoder->private_->seek_table));
+
+		if(encoder->private_->seek_callback(encoder, encoder->protected_->seektable_offset + FLAC__STREAM_METADATA_HEADER_LENGTH, encoder->private_->client_data) != FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_OK) {
+			encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_SEEK_ERROR;
+			return;
+		}
+
+		for(i = 0; i < encoder->private_->seek_table->num_points; i++) {
+			FLAC__uint64 xx;
+			unsigned x;
+			xx = encoder->private_->seek_table->points[i].sample_number;
+			b[7] = (FLAC__byte)xx; xx >>= 8;
+			b[6] = (FLAC__byte)xx; xx >>= 8;
+			b[5] = (FLAC__byte)xx; xx >>= 8;
+			b[4] = (FLAC__byte)xx; xx >>= 8;
+			b[3] = (FLAC__byte)xx; xx >>= 8;
+			b[2] = (FLAC__byte)xx; xx >>= 8;
+			b[1] = (FLAC__byte)xx; xx >>= 8;
+			b[0] = (FLAC__byte)xx; xx >>= 8;
+			xx = encoder->private_->seek_table->points[i].stream_offset;
+			b[15] = (FLAC__byte)xx; xx >>= 8;
+			b[14] = (FLAC__byte)xx; xx >>= 8;
+			b[13] = (FLAC__byte)xx; xx >>= 8;
+			b[12] = (FLAC__byte)xx; xx >>= 8;
+			b[11] = (FLAC__byte)xx; xx >>= 8;
+			b[10] = (FLAC__byte)xx; xx >>= 8;
+			b[9] = (FLAC__byte)xx; xx >>= 8;
+			b[8] = (FLAC__byte)xx; xx >>= 8;
+			x = encoder->private_->seek_table->points[i].frame_samples;
+			b[17] = (FLAC__byte)x; x >>= 8;
+			b[16] = (FLAC__byte)x; x >>= 8;
+			if(encoder->private_->write_callback(encoder, b, 18, 0, 0, encoder->private_->client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) {
+				encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_WRITE_ERROR;
+				return;
+			}
+		}
+	}
+}
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/stream_decoder.c
@@ -1,0 +1,2112 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h> /* for malloc() */
+#include <string.h> /* for memset/memcpy() */
+#include "FLAC/assert.h"
+#include "protected/stream_decoder.h"
+#include "private/bitbuffer.h"
+#include "private/bitmath.h"
+#include "private/cpu.h"
+#include "private/crc.h"
+#include "private/fixed.h"
+#include "private/format.h"
+#include "private/lpc.h"
+#include "private/memory.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef max
+#undef max
+#endif
+#define max(a,b) ((a)>(b)?(a):(b))
+
+/* adjust for compilers that can't understand using LLU suffix for uint64_t literals */
+#ifdef _MSC_VER
+#define FLAC__U64L(x) x
+#else
+#define FLAC__U64L(x) x##LLU
+#endif
+
+/***********************************************************************
+ *
+ * Private static data
+ *
+ ***********************************************************************/
+
+static FLAC__byte ID3V2_TAG_[3] = { 'I', 'D', '3' };
+
+/***********************************************************************
+ *
+ * Private class method prototypes
+ *
+ ***********************************************************************/
+
+static void set_defaults_(FLAC__StreamDecoder *decoder);
+static FLAC__bool allocate_output_(FLAC__StreamDecoder *decoder, unsigned size, unsigned channels);
+static FLAC__bool has_id_filtered_(FLAC__StreamDecoder *decoder, FLAC__byte *id);
+static FLAC__bool find_metadata_(FLAC__StreamDecoder *decoder);
+static FLAC__bool read_metadata_(FLAC__StreamDecoder *decoder);
+static FLAC__bool read_metadata_streaminfo_(FLAC__StreamDecoder *decoder, FLAC__bool is_last, unsigned length);
+static FLAC__bool read_metadata_seektable_(FLAC__StreamDecoder *decoder, FLAC__bool is_last, unsigned length);
+static FLAC__bool read_metadata_vorbiscomment_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_VorbisComment *obj);
+static FLAC__bool read_metadata_cuesheet_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_CueSheet *obj);
+static FLAC__bool skip_id3v2_tag_(FLAC__StreamDecoder *decoder);
+static FLAC__bool frame_sync_(FLAC__StreamDecoder *decoder);
+static FLAC__bool read_frame_(FLAC__StreamDecoder *decoder, FLAC__bool *got_a_frame, FLAC__bool do_full_decode);
+static FLAC__bool read_frame_header_(FLAC__StreamDecoder *decoder);
+static FLAC__bool read_subframe_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, FLAC__bool do_full_decode);
+static FLAC__bool read_subframe_constant_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, FLAC__bool do_full_decode);
+static FLAC__bool read_subframe_fixed_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, const unsigned order, FLAC__bool do_full_decode);
+static FLAC__bool read_subframe_lpc_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, const unsigned order, FLAC__bool do_full_decode);
+static FLAC__bool read_subframe_verbatim_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, FLAC__bool do_full_decode);
+static FLAC__bool read_residual_partitioned_rice_(FLAC__StreamDecoder *decoder, unsigned predictor_order, unsigned partition_order, FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents, FLAC__int32 *residual);
+static FLAC__bool read_zero_padding_(FLAC__StreamDecoder *decoder);
+static FLAC__bool read_callback_(FLAC__byte buffer[], unsigned *bytes, void *client_data);
+
+/***********************************************************************
+ *
+ * Private class data
+ *
+ ***********************************************************************/
+
+typedef struct FLAC__StreamDecoderPrivate {
+	FLAC__StreamDecoderReadCallback read_callback;
+	FLAC__StreamDecoderWriteCallback write_callback;
+	FLAC__StreamDecoderMetadataCallback metadata_callback;
+	FLAC__StreamDecoderErrorCallback error_callback;
+	/* generic 32-bit datapath: */
+	void (*local_lpc_restore_signal)(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]);
+	/* generic 64-bit datapath: */
+	void (*local_lpc_restore_signal_64bit)(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]);
+	/* for use when the signal is <= 16 bits-per-sample, or <= 15 bits-per-sample on a side channel (which requires 1 extra bit): */
+	void (*local_lpc_restore_signal_16bit)(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]);
+	/* for use when the signal is <= 16 bits-per-sample, or <= 15 bits-per-sample on a side channel (which requires 1 extra bit), AND order <= 8: */
+	void (*local_lpc_restore_signal_16bit_order8)(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]);
+	void *client_data;
+	FLAC__BitBuffer *input;
+	FLAC__int32 *output[FLAC__MAX_CHANNELS];
+	FLAC__int32 *residual[FLAC__MAX_CHANNELS]; /* WATCHOUT: these are the aligned pointers; the real pointers that should be free()'d are residual_unaligned[] below */
+	FLAC__EntropyCodingMethod_PartitionedRiceContents partitioned_rice_contents[FLAC__MAX_CHANNELS];
+	unsigned output_capacity, output_channels;
+	FLAC__uint32 last_frame_number;
+	FLAC__uint64 samples_decoded;
+	FLAC__bool has_stream_info, has_seek_table;
+	FLAC__StreamMetadata stream_info;
+	FLAC__StreamMetadata seek_table;
+	FLAC__bool metadata_filter[128]; /* MAGIC number 128 == total number of metadata block types == 1 << 7 */
+	FLAC__byte *metadata_filter_ids;
+	unsigned metadata_filter_ids_count, metadata_filter_ids_capacity; /* units for both are IDs, not bytes */
+	FLAC__Frame frame;
+	FLAC__bool cached; /* true if there is a byte in lookahead */
+	FLAC__CPUInfo cpuinfo;
+	FLAC__byte header_warmup[2]; /* contains the sync code and reserved bits */
+	FLAC__byte lookahead; /* temp storage when we need to look ahead one byte in the stream */
+	/* unaligned (original) pointers to allocated data */
+	FLAC__int32 *residual_unaligned[FLAC__MAX_CHANNELS];
+} FLAC__StreamDecoderPrivate;
+
+/***********************************************************************
+ *
+ * Public static class data
+ *
+ ***********************************************************************/
+
+FLAC_API const char * const FLAC__StreamDecoderStateString[] = {
+	"FLAC__STREAM_DECODER_SEARCH_FOR_METADATA",
+	"FLAC__STREAM_DECODER_READ_METADATA",
+	"FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC",
+	"FLAC__STREAM_DECODER_READ_FRAME",
+	"FLAC__STREAM_DECODER_END_OF_STREAM",
+	"FLAC__STREAM_DECODER_ABORTED",
+	"FLAC__STREAM_DECODER_UNPARSEABLE_STREAM",
+	"FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR",
+	"FLAC__STREAM_DECODER_ALREADY_INITIALIZED",
+	"FLAC__STREAM_DECODER_INVALID_CALLBACK",
+	"FLAC__STREAM_DECODER_UNINITIALIZED"
+};
+
+FLAC_API const char * const FLAC__StreamDecoderReadStatusString[] = {
+	"FLAC__STREAM_DECODER_READ_STATUS_CONTINUE",
+	"FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM",
+	"FLAC__STREAM_DECODER_READ_STATUS_ABORT"
+};
+
+FLAC_API const char * const FLAC__StreamDecoderWriteStatusString[] = {
+	"FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE",
+	"FLAC__STREAM_DECODER_WRITE_STATUS_ABORT"
+};
+
+FLAC_API const char * const FLAC__StreamDecoderErrorStatusString[] = {
+	"FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC",
+	"FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER",
+	"FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH"
+};
+
+/***********************************************************************
+ *
+ * Class constructor/destructor
+ *
+ ***********************************************************************/
+FLAC_API FLAC__StreamDecoder *FLAC__stream_decoder_new()
+{
+	FLAC__StreamDecoder *decoder;
+	unsigned i;
+
+	FLAC__ASSERT(sizeof(int) >= 4); /* we want to die right away if this is not true */
+
+	decoder = (FLAC__StreamDecoder*)calloc(1, sizeof(FLAC__StreamDecoder));
+	if(decoder == 0) {
+		return 0;
+	}
+
+	decoder->protected_ = (FLAC__StreamDecoderProtected*)calloc(1, sizeof(FLAC__StreamDecoderProtected));
+	if(decoder->protected_ == 0) {
+		free(decoder);
+		return 0;
+	}
+
+	decoder->private_ = (FLAC__StreamDecoderPrivate*)calloc(1, sizeof(FLAC__StreamDecoderPrivate));
+	if(decoder->private_ == 0) {
+		free(decoder->protected_);
+		free(decoder);
+		return 0;
+	}
+
+	decoder->private_->input = FLAC__bitbuffer_new();
+	if(decoder->private_->input == 0) {
+		free(decoder->private_);
+		free(decoder->protected_);
+		free(decoder);
+		return 0;
+	}
+
+	decoder->private_->metadata_filter_ids_capacity = 16;
+	if(0 == (decoder->private_->metadata_filter_ids = (FLAC__byte*)malloc((FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) * decoder->private_->metadata_filter_ids_capacity))) {
+		FLAC__bitbuffer_delete(decoder->private_->input);
+		free(decoder->private_);
+		free(decoder->protected_);
+		free(decoder);
+		return 0;
+	}
+
+	for(i = 0; i < FLAC__MAX_CHANNELS; i++) {
+		decoder->private_->output[i] = 0;
+		decoder->private_->residual_unaligned[i] = decoder->private_->residual[i] = 0;
+	}
+
+	decoder->private_->output_capacity = 0;
+	decoder->private_->output_channels = 0;
+	decoder->private_->has_seek_table = false;
+
+	for(i = 0; i < FLAC__MAX_CHANNELS; i++)
+		FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&decoder->private_->partitioned_rice_contents[i]);
+
+	set_defaults_(decoder);
+
+	decoder->protected_->state = FLAC__STREAM_DECODER_UNINITIALIZED;
+
+	return decoder;
+}
+
+FLAC_API void FLAC__stream_decoder_delete(FLAC__StreamDecoder *decoder)
+{
+	unsigned i;
+
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->protected_);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->private_->input);
+
+	FLAC__stream_decoder_finish(decoder);
+
+	if(0 != decoder->private_->metadata_filter_ids)
+		free(decoder->private_->metadata_filter_ids);
+
+	FLAC__bitbuffer_delete(decoder->private_->input);
+
+	for(i = 0; i < FLAC__MAX_CHANNELS; i++)
+		FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&decoder->private_->partitioned_rice_contents[i]);
+
+	free(decoder->private_);
+	free(decoder->protected_);
+	free(decoder);
+}
+
+/***********************************************************************
+ *
+ * Public class methods
+ *
+ ***********************************************************************/
+
+FLAC_API FLAC__StreamDecoderState FLAC__stream_decoder_init(FLAC__StreamDecoder *decoder)
+{
+	FLAC__ASSERT(0 != decoder);
+
+	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+		return decoder->protected_->state = FLAC__STREAM_DECODER_ALREADY_INITIALIZED;
+
+	if(0 == decoder->private_->read_callback || 0 == decoder->private_->write_callback || 0 == decoder->private_->metadata_callback || 0 == decoder->private_->error_callback)
+		return decoder->protected_->state = FLAC__STREAM_DECODER_INVALID_CALLBACK;
+
+	if(!FLAC__bitbuffer_init(decoder->private_->input))
+		return decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+
+	decoder->private_->last_frame_number = 0;
+	decoder->private_->samples_decoded = 0;
+	decoder->private_->has_stream_info = false;
+	decoder->private_->cached = false;
+
+	/*
+	 * get the CPU info and set the function pointers
+	 */
+	FLAC__cpu_info(&decoder->private_->cpuinfo);
+	/* first default to the non-asm routines */
+	decoder->private_->local_lpc_restore_signal = FLAC__lpc_restore_signal;
+	decoder->private_->local_lpc_restore_signal_64bit = FLAC__lpc_restore_signal_wide;
+	decoder->private_->local_lpc_restore_signal_16bit = FLAC__lpc_restore_signal;
+	decoder->private_->local_lpc_restore_signal_16bit_order8 = FLAC__lpc_restore_signal;
+	/* now override with asm where appropriate */
+#ifndef FLAC__NO_ASM
+	if(decoder->private_->cpuinfo.use_asm) {
+#ifdef FLAC__CPU_IA32
+		FLAC__ASSERT(decoder->private_->cpuinfo.type == FLAC__CPUINFO_TYPE_IA32);
+#ifdef FLAC__HAS_NASM
+		if(decoder->private_->cpuinfo.data.ia32.mmx) {
+			decoder->private_->local_lpc_restore_signal = FLAC__lpc_restore_signal_asm_ia32;
+			decoder->private_->local_lpc_restore_signal_16bit = FLAC__lpc_restore_signal_asm_ia32_mmx;
+			decoder->private_->local_lpc_restore_signal_16bit_order8 = FLAC__lpc_restore_signal_asm_ia32_mmx;
+		}
+		else {
+			decoder->private_->local_lpc_restore_signal = FLAC__lpc_restore_signal_asm_ia32;
+			decoder->private_->local_lpc_restore_signal_16bit = FLAC__lpc_restore_signal_asm_ia32;
+			decoder->private_->local_lpc_restore_signal_16bit_order8 = FLAC__lpc_restore_signal_asm_ia32;
+		}
+#endif
+#elif defined FLAC__CPU_PPC
+		FLAC__ASSERT(decoder->private_->cpuinfo.type == FLAC__CPUINFO_TYPE_PPC);
+		if(decoder->private_->cpuinfo.data.ppc.altivec) {
+			decoder->private_->local_lpc_restore_signal_16bit = FLAC__lpc_restore_signal_asm_ppc_altivec_16;
+			decoder->private_->local_lpc_restore_signal_16bit_order8 = FLAC__lpc_restore_signal_asm_ppc_altivec_16_order8;
+		}
+#endif
+	}
+#endif
+
+	if(!FLAC__stream_decoder_reset(decoder))
+		return decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+
+	return decoder->protected_->state;
+}
+
+FLAC_API void FLAC__stream_decoder_finish(FLAC__StreamDecoder *decoder)
+{
+	unsigned i;
+	FLAC__ASSERT(0 != decoder);
+	if(decoder->protected_->state == FLAC__STREAM_DECODER_UNINITIALIZED)
+		return;
+	if(0 != decoder->private_->seek_table.data.seek_table.points) {
+		free(decoder->private_->seek_table.data.seek_table.points);
+		decoder->private_->seek_table.data.seek_table.points = 0;
+		decoder->private_->has_seek_table = false;
+	}
+	FLAC__bitbuffer_free(decoder->private_->input);
+	for(i = 0; i < FLAC__MAX_CHANNELS; i++) {
+		/* WATCHOUT:
+		 * FLAC__lpc_restore_signal_asm_ia32_mmx() requires that the
+		 * output arrays have a buffer of up to 3 zeroes in front
+		 * (at negative indices) for alignment purposes; we use 4
+		 * to keep the data well-aligned.
+		 */
+		if(0 != decoder->private_->output[i]) {
+			free(decoder->private_->output[i]-4);
+			decoder->private_->output[i] = 0;
+		}
+		if(0 != decoder->private_->residual_unaligned[i]) {
+			free(decoder->private_->residual_unaligned[i]);
+			decoder->private_->residual_unaligned[i] = decoder->private_->residual[i] = 0;
+		}
+	}
+	decoder->private_->output_capacity = 0;
+	decoder->private_->output_channels = 0;
+
+	set_defaults_(decoder);
+
+	decoder->protected_->state = FLAC__STREAM_DECODER_UNINITIALIZED;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_set_read_callback(FLAC__StreamDecoder *decoder, FLAC__StreamDecoderReadCallback value)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->protected_);
+	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+		return false;
+	decoder->private_->read_callback = value;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_set_write_callback(FLAC__StreamDecoder *decoder, FLAC__StreamDecoderWriteCallback value)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->protected_);
+	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+		return false;
+	decoder->private_->write_callback = value;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_callback(FLAC__StreamDecoder *decoder, FLAC__StreamDecoderMetadataCallback value)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->protected_);
+	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+		return false;
+	decoder->private_->metadata_callback = value;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_set_error_callback(FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorCallback value)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->protected_);
+	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+		return false;
+	decoder->private_->error_callback = value;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_set_client_data(FLAC__StreamDecoder *decoder, void *value)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->protected_);
+	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+		return false;
+	decoder->private_->client_data = value;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond(FLAC__StreamDecoder *decoder, FLAC__MetadataType type)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->protected_);
+	FLAC__ASSERT((unsigned)type <= FLAC__MAX_METADATA_TYPE_CODE);
+	/* double protection */
+	if((unsigned)type > FLAC__MAX_METADATA_TYPE_CODE)
+		return false;
+	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+		return false;
+	decoder->private_->metadata_filter[type] = true;
+	if(type == FLAC__METADATA_TYPE_APPLICATION)
+		decoder->private_->metadata_filter_ids_count = 0;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond_application(FLAC__StreamDecoder *decoder, const FLAC__byte id[4])
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->protected_);
+	FLAC__ASSERT(0 != id);
+	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+		return false;
+
+	if(decoder->private_->metadata_filter[FLAC__METADATA_TYPE_APPLICATION])
+		return true;
+
+	FLAC__ASSERT(0 != decoder->private_->metadata_filter_ids);
+
+	if(decoder->private_->metadata_filter_ids_count == decoder->private_->metadata_filter_ids_capacity) {
+		if(0 == (decoder->private_->metadata_filter_ids = (FLAC__byte*)realloc(decoder->private_->metadata_filter_ids, decoder->private_->metadata_filter_ids_capacity * 2)))
+			return decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+		decoder->private_->metadata_filter_ids_capacity *= 2;
+	}
+
+	memcpy(decoder->private_->metadata_filter_ids + decoder->private_->metadata_filter_ids_count * (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), id, (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8));
+	decoder->private_->metadata_filter_ids_count++;
+
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond_all(FLAC__StreamDecoder *decoder)
+{
+	unsigned i;
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->protected_);
+	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+		return false;
+	for(i = 0; i < sizeof(decoder->private_->metadata_filter) / sizeof(decoder->private_->metadata_filter[0]); i++)
+		decoder->private_->metadata_filter[i] = true;
+	decoder->private_->metadata_filter_ids_count = 0;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore(FLAC__StreamDecoder *decoder, FLAC__MetadataType type)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->protected_);
+	FLAC__ASSERT((unsigned)type <= FLAC__MAX_METADATA_TYPE_CODE);
+	/* double protection */
+	if((unsigned)type > FLAC__MAX_METADATA_TYPE_CODE)
+		return false;
+	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+		return false;
+	decoder->private_->metadata_filter[type] = false;
+	if(type == FLAC__METADATA_TYPE_APPLICATION)
+		decoder->private_->metadata_filter_ids_count = 0;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore_application(FLAC__StreamDecoder *decoder, const FLAC__byte id[4])
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->protected_);
+	FLAC__ASSERT(0 != id);
+	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+		return false;
+
+	if(!decoder->private_->metadata_filter[FLAC__METADATA_TYPE_APPLICATION])
+		return true;
+
+	FLAC__ASSERT(0 != decoder->private_->metadata_filter_ids);
+
+	if(decoder->private_->metadata_filter_ids_count == decoder->private_->metadata_filter_ids_capacity) {
+		if(0 == (decoder->private_->metadata_filter_ids = (FLAC__byte*)realloc(decoder->private_->metadata_filter_ids, decoder->private_->metadata_filter_ids_capacity * 2)))
+			return decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+		decoder->private_->metadata_filter_ids_capacity *= 2;
+	}
+
+	memcpy(decoder->private_->metadata_filter_ids + decoder->private_->metadata_filter_ids_count * (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), id, (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8));
+	decoder->private_->metadata_filter_ids_count++;
+
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore_all(FLAC__StreamDecoder *decoder)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->protected_);
+	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+		return false;
+	memset(decoder->private_->metadata_filter, 0, sizeof(decoder->private_->metadata_filter));
+	decoder->private_->metadata_filter_ids_count = 0;
+	return true;
+}
+
+FLAC_API FLAC__StreamDecoderState FLAC__stream_decoder_get_state(const FLAC__StreamDecoder *decoder)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->protected_);
+	return decoder->protected_->state;
+}
+
+FLAC_API const char *FLAC__stream_decoder_get_resolved_state_string(const FLAC__StreamDecoder *decoder)
+{
+	return FLAC__StreamDecoderStateString[decoder->protected_->state];
+}
+
+FLAC_API unsigned FLAC__stream_decoder_get_channels(const FLAC__StreamDecoder *decoder)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->protected_);
+	return decoder->protected_->channels;
+}
+
+FLAC_API FLAC__ChannelAssignment FLAC__stream_decoder_get_channel_assignment(const FLAC__StreamDecoder *decoder)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->protected_);
+	return decoder->protected_->channel_assignment;
+}
+
+FLAC_API unsigned FLAC__stream_decoder_get_bits_per_sample(const FLAC__StreamDecoder *decoder)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->protected_);
+	return decoder->protected_->bits_per_sample;
+}
+
+FLAC_API unsigned FLAC__stream_decoder_get_sample_rate(const FLAC__StreamDecoder *decoder)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->protected_);
+	return decoder->protected_->sample_rate;
+}
+
+FLAC_API unsigned FLAC__stream_decoder_get_blocksize(const FLAC__StreamDecoder *decoder)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->protected_);
+	return decoder->protected_->blocksize;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_flush(FLAC__StreamDecoder *decoder)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->protected_);
+
+	if(!FLAC__bitbuffer_clear(decoder->private_->input)) {
+		decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+		return false;
+	}
+	decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_reset(FLAC__StreamDecoder *decoder)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != decoder->protected_);
+
+	if(!FLAC__stream_decoder_flush(decoder)) {
+		decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+		return false;
+	}
+	decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_METADATA;
+
+	decoder->private_->samples_decoded = 0;
+
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_process_single(FLAC__StreamDecoder *decoder)
+{
+	FLAC__bool got_a_frame;
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->protected_);
+
+	while(1) {
+		switch(decoder->protected_->state) {
+			case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA:
+				if(!find_metadata_(decoder))
+					return false; /* above function sets the status for us */
+				break;
+			case FLAC__STREAM_DECODER_READ_METADATA:
+				if(!read_metadata_(decoder))
+					return false; /* above function sets the status for us */
+				else
+					return true;
+			case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC:
+				if(!frame_sync_(decoder))
+					return true; /* above function sets the status for us */
+				break;
+			case FLAC__STREAM_DECODER_READ_FRAME:
+				if(!read_frame_(decoder, &got_a_frame, /*do_full_decode=*/true))
+					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:
+			case FLAC__STREAM_DECODER_ABORTED:
+				return true;
+			default:
+				FLAC__ASSERT(0);
+				return false;
+		}
+	}
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_metadata(FLAC__StreamDecoder *decoder)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->protected_);
+
+	while(1) {
+		switch(decoder->protected_->state) {
+			case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA:
+				if(!find_metadata_(decoder))
+					return false; /* above function sets the status for us */
+				break;
+			case FLAC__STREAM_DECODER_READ_METADATA:
+				if(!read_metadata_(decoder))
+					return false; /* above function sets the status for us */
+				break;
+			case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC:
+			case FLAC__STREAM_DECODER_READ_FRAME:
+			case FLAC__STREAM_DECODER_END_OF_STREAM:
+			case FLAC__STREAM_DECODER_ABORTED:
+				return true;
+			default:
+				FLAC__ASSERT(0);
+				return false;
+		}
+	}
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_stream(FLAC__StreamDecoder *decoder)
+{
+	FLAC__bool dummy;
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->protected_);
+
+	while(1) {
+		switch(decoder->protected_->state) {
+			case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA:
+				if(!find_metadata_(decoder))
+					return false; /* above function sets the status for us */
+				break;
+			case FLAC__STREAM_DECODER_READ_METADATA:
+				if(!read_metadata_(decoder))
+					return false; /* above function sets the status for us */
+				break;
+			case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC:
+				if(!frame_sync_(decoder))
+					return true; /* above function sets the status for us */
+				break;
+			case FLAC__STREAM_DECODER_READ_FRAME:
+				if(!read_frame_(decoder, &dummy, /*do_full_decode=*/true))
+					return false; /* above function sets the status for us */
+				break;
+			case FLAC__STREAM_DECODER_END_OF_STREAM:
+			case FLAC__STREAM_DECODER_ABORTED:
+				return true;
+			default:
+				FLAC__ASSERT(0);
+				return false;
+		}
+	}
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_skip_single_frame(FLAC__StreamDecoder *decoder)
+{
+	FLAC__bool got_a_frame;
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->protected_);
+
+	while(1) {
+		switch(decoder->protected_->state) {
+			case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA:
+			case FLAC__STREAM_DECODER_READ_METADATA:
+				return false; /* above function sets the status for us */
+			case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC:
+				if(!frame_sync_(decoder))
+					return true; /* above function sets the status for us */
+				break;
+			case FLAC__STREAM_DECODER_READ_FRAME:
+				if(!read_frame_(decoder, &got_a_frame, /*do_full_decode=*/false))
+					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:
+			case FLAC__STREAM_DECODER_ABORTED:
+				return true;
+			default:
+				FLAC__ASSERT(0);
+				return false;
+		}
+	}
+}
+
+/***********************************************************************
+ *
+ * Protected class methods
+ *
+ ***********************************************************************/
+
+unsigned FLAC__stream_decoder_get_input_bytes_unconsumed(const FLAC__StreamDecoder *decoder)
+{
+	FLAC__ASSERT(0 != decoder);
+	return FLAC__bitbuffer_get_input_bytes_unconsumed(decoder->private_->input);
+}
+
+/***********************************************************************
+ *
+ * Private class methods
+ *
+ ***********************************************************************/
+
+void set_defaults_(FLAC__StreamDecoder *decoder)
+{
+	decoder->private_->read_callback = 0;
+	decoder->private_->write_callback = 0;
+	decoder->private_->metadata_callback = 0;
+	decoder->private_->error_callback = 0;
+	decoder->private_->client_data = 0;
+
+	memset(decoder->private_->metadata_filter, 0, sizeof(decoder->private_->metadata_filter));
+	decoder->private_->metadata_filter[FLAC__METADATA_TYPE_STREAMINFO] = true;
+	decoder->private_->metadata_filter_ids_count = 0;
+}
+
+FLAC__bool allocate_output_(FLAC__StreamDecoder *decoder, unsigned size, unsigned channels)
+{
+	unsigned i;
+	FLAC__int32 *tmp;
+
+	if(size <= decoder->private_->output_capacity && channels <= decoder->private_->output_channels)
+		return true;
+
+	/* simply using realloc() is not practical because the number of channels may change mid-stream */
+
+	for(i = 0; i < FLAC__MAX_CHANNELS; i++) {
+		if(0 != decoder->private_->output[i]) {
+			free(decoder->private_->output[i]-4);
+			decoder->private_->output[i] = 0;
+		}
+		if(0 != decoder->private_->residual_unaligned[i]) {
+			free(decoder->private_->residual_unaligned[i]);
+			decoder->private_->residual_unaligned[i] = decoder->private_->residual[i] = 0;
+		}
+	}
+
+	for(i = 0; i < channels; i++) {
+		/* WATCHOUT:
+		 * FLAC__lpc_restore_signal_asm_ia32_mmx() requires that the
+		 * output arrays have a buffer of up to 3 zeroes in front
+		 * (at negative indices) for alignment purposes; we use 4
+		 * to keep the data well-aligned.
+		 */
+		tmp = (FLAC__int32*)malloc(sizeof(FLAC__int32)*(size+4));
+		if(tmp == 0) {
+			decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+			return false;
+		}
+		memset(tmp, 0, sizeof(FLAC__int32)*4);
+		decoder->private_->output[i] = tmp + 4;
+
+		/* WATCHOUT:
+		 * minimum of quadword alignment for PPC vector optimizations is REQUIRED:
+		 */
+		if(!FLAC__memory_alloc_aligned_int32_array(size, &decoder->private_->residual_unaligned[i], &decoder->private_->residual[i])) {
+			decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+			return false;
+		}
+	}
+
+	decoder->private_->output_capacity = size;
+	decoder->private_->output_channels = channels;
+
+	return true;
+}
+
+FLAC__bool has_id_filtered_(FLAC__StreamDecoder *decoder, FLAC__byte *id)
+{
+	unsigned i;
+
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+
+	for(i = 0; i < decoder->private_->metadata_filter_ids_count; i++)
+		if(0 == memcmp(decoder->private_->metadata_filter_ids + i * (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), id, (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8)))
+			return true;
+
+	return false;
+}
+
+FLAC__bool find_metadata_(FLAC__StreamDecoder *decoder)
+{
+	FLAC__uint32 x;
+	unsigned i, id;
+	FLAC__bool first = true;
+
+	FLAC__ASSERT(FLAC__bitbuffer_is_consumed_byte_aligned(decoder->private_->input));
+
+	for(i = id = 0; i < 4; ) {
+		if(decoder->private_->cached) {
+			x = (FLAC__uint32)decoder->private_->lookahead;
+			decoder->private_->cached = false;
+		}
+		else {
+			if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, 8, read_callback_, decoder))
+				return false; /* the read_callback_ sets the state for us */
+		}
+		if(x == FLAC__STREAM_SYNC_STRING[i]) {
+			first = true;
+			i++;
+			id = 0;
+			continue;
+		}
+		if(x == ID3V2_TAG_[id]) {
+			id++;
+			i = 0;
+			if(id == 3) {
+				if(!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 */
+			decoder->private_->header_warmup[0] = (FLAC__byte)x;
+			if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, 8, read_callback_, decoder))
+				return false; /* the read_callback_ sets the state for us */
+
+			/* we have to check if we just read two 0xff's in a row; the second may actually be the beginning of the sync code */
+			/* else we have to check if the second byte is the end of a sync code */
+			if(x == 0xff) { /* MAGIC NUMBER for the first 8 frame sync bits */
+				decoder->private_->lookahead = (FLAC__byte)x;
+				decoder->private_->cached = true;
+			}
+			else if(x >> 2 == 0x3e) { /* MAGIC NUMBER for the last 6 sync bits */
+				decoder->private_->header_warmup[1] = (FLAC__byte)x;
+				decoder->protected_->state = FLAC__STREAM_DECODER_READ_FRAME;
+				return true;
+			}
+		}
+		i = 0;
+		if(first) {
+			decoder->private_->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC, decoder->private_->client_data);
+			first = false;
+		}
+	}
+
+	decoder->protected_->state = FLAC__STREAM_DECODER_READ_METADATA;
+	return true;
+}
+
+FLAC__bool read_metadata_(FLAC__StreamDecoder *decoder)
+{
+	FLAC__bool is_last;
+	FLAC__uint32 i, x, type, length;
+
+	FLAC__ASSERT(FLAC__bitbuffer_is_consumed_byte_aligned(decoder->private_->input));
+
+	if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_IS_LAST_LEN, read_callback_, decoder))
+		return false; /* the read_callback_ sets the state for us */
+	is_last = x? true : false;
+
+	if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->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->private_->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_STREAMINFO) {
+		if(!read_metadata_streaminfo_(decoder, is_last, length))
+			return false;
+
+		decoder->private_->has_stream_info = true;
+		if(decoder->private_->metadata_filter[FLAC__METADATA_TYPE_STREAMINFO])
+			decoder->private_->metadata_callback(decoder, &decoder->private_->stream_info, decoder->private_->client_data);
+	}
+	else if(type == FLAC__METADATA_TYPE_SEEKTABLE) {
+		if(!read_metadata_seektable_(decoder, is_last, length))
+			return false;
+
+		decoder->private_->has_seek_table = true;
+		if(decoder->private_->metadata_filter[FLAC__METADATA_TYPE_SEEKTABLE])
+			decoder->private_->metadata_callback(decoder, &decoder->private_->seek_table, decoder->private_->client_data);
+	}
+	else {
+		FLAC__bool skip_it = !decoder->private_->metadata_filter[type];
+		unsigned real_length = length;
+		FLAC__StreamMetadata block;
+
+		block.is_last = is_last;
+		block.type = (FLAC__MetadataType)type;
+		block.length = length;
+
+		if(type == FLAC__METADATA_TYPE_APPLICATION) {
+			if(!FLAC__bitbuffer_read_byte_block_aligned_no_crc(decoder->private_->input, block.data.application.id, FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8, read_callback_, decoder))
+				return false; /* the read_callback_ sets the state for us */
+
+			real_length -= FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8;
+
+			if(decoder->private_->metadata_filter_ids_count > 0 && has_id_filtered_(decoder, block.data.application.id))
+				skip_it = !skip_it;
+		}
+
+		if(skip_it) {
+			if(!FLAC__bitbuffer_read_byte_block_aligned_no_crc(decoder->private_->input, 0, real_length, read_callback_, decoder))
+				return false; /* the read_callback_ sets the state for us */
+		}
+		else {
+			switch(type) {
+				case FLAC__METADATA_TYPE_PADDING:
+					/* skip the padding bytes */
+					if(!FLAC__bitbuffer_read_byte_block_aligned_no_crc(decoder->private_->input, 0, real_length, read_callback_, decoder))
+						return false; /* the read_callback_ sets the state for us */
+					break;
+				case FLAC__METADATA_TYPE_APPLICATION:
+					/* remember, we read the ID already */
+					if(real_length > 0) {
+						if(0 == (block.data.application.data = (FLAC__byte*)malloc(real_length))) {
+							decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+							return false;
+						}
+						if(!FLAC__bitbuffer_read_byte_block_aligned_no_crc(decoder->private_->input, block.data.application.data, real_length, read_callback_, decoder))
+							return false; /* the read_callback_ sets the state for us */
+					}
+					else
+						block.data.application.data = 0;
+					break;
+				case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+					if(!read_metadata_vorbiscomment_(decoder, &block.data.vorbis_comment))
+						return false;
+					break;
+				case FLAC__METADATA_TYPE_CUESHEET:
+					if(!read_metadata_cuesheet_(decoder, &block.data.cue_sheet))
+						return false;
+					break;
+				case FLAC__METADATA_TYPE_STREAMINFO:
+				case FLAC__METADATA_TYPE_SEEKTABLE:
+					FLAC__ASSERT(0);
+					break;
+				default:
+					if(real_length > 0) {
+						if(0 == (block.data.unknown.data = (FLAC__byte*)malloc(real_length))) {
+							decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+							return false;
+						}
+						if(!FLAC__bitbuffer_read_byte_block_aligned_no_crc(decoder->private_->input, block.data.unknown.data, real_length, read_callback_, decoder))
+							return false; /* the read_callback_ sets the state for us */
+					}
+					else
+						block.data.unknown.data = 0;
+					break;
+			}
+			decoder->private_->metadata_callback(decoder, &block, decoder->private_->client_data);
+
+			/* now we have to free any malloc'ed data in the block */
+			switch(type) {
+				case FLAC__METADATA_TYPE_PADDING:
+					break;
+				case FLAC__METADATA_TYPE_APPLICATION:
+					if(0 != block.data.application.data)
+						free(block.data.application.data);
+					break;
+				case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+					if(0 != block.data.vorbis_comment.vendor_string.entry)
+						free(block.data.vorbis_comment.vendor_string.entry);
+					if(block.data.vorbis_comment.num_comments > 0)
+						for(i = 0; i < block.data.vorbis_comment.num_comments; i++)
+							if(0 != block.data.vorbis_comment.comments[i].entry)
+								free(block.data.vorbis_comment.comments[i].entry);
+					if(0 != block.data.vorbis_comment.comments)
+						free(block.data.vorbis_comment.comments);
+					break;
+				case FLAC__METADATA_TYPE_CUESHEET:
+					if(block.data.cue_sheet.num_tracks > 0)
+						for(i = 0; i < block.data.cue_sheet.num_tracks; i++)
+							if(0 != block.data.cue_sheet.tracks[i].indices)
+								free(block.data.cue_sheet.tracks[i].indices);
+					if(0 != block.data.cue_sheet.tracks)
+						free(block.data.cue_sheet.tracks);
+					break;
+				case FLAC__METADATA_TYPE_STREAMINFO:
+				case FLAC__METADATA_TYPE_SEEKTABLE:
+					FLAC__ASSERT(0);
+				default:
+					if(0 != block.data.unknown.data)
+						free(block.data.unknown.data);
+					break;
+			}
+		}
+	}
+
+	if(is_last)
+		decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+
+	return true;
+}
+
+FLAC__bool read_metadata_streaminfo_(FLAC__StreamDecoder *decoder, FLAC__bool is_last, unsigned length)
+{
+	FLAC__uint32 x;
+	unsigned bits, used_bits = 0;
+
+	FLAC__ASSERT(FLAC__bitbuffer_is_consumed_byte_aligned(decoder->private_->input));
+
+	decoder->private_->stream_info.type = FLAC__METADATA_TYPE_STREAMINFO;
+	decoder->private_->stream_info.is_last = is_last;
+	decoder->private_->stream_info.length = length;
+
+	bits = FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN;
+	if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, bits, read_callback_, decoder))
+		return false; /* the read_callback_ sets the state for us */
+	decoder->private_->stream_info.data.stream_info.min_blocksize = x;
+	used_bits += bits;
+
+	bits = FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN;
+	if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN, read_callback_, decoder))
+		return false; /* the read_callback_ sets the state for us */
+	decoder->private_->stream_info.data.stream_info.max_blocksize = x;
+	used_bits += bits;
+
+	bits = FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN;
+	if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN, read_callback_, decoder))
+		return false; /* the read_callback_ sets the state for us */
+	decoder->private_->stream_info.data.stream_info.min_framesize = x;
+	used_bits += bits;
+
+	bits = FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN;
+	if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN, read_callback_, decoder))
+		return false; /* the read_callback_ sets the state for us */
+	decoder->private_->stream_info.data.stream_info.max_framesize = x;
+	used_bits += bits;
+
+	bits = FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN;
+	if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN, read_callback_, decoder))
+		return false; /* the read_callback_ sets the state for us */
+	decoder->private_->stream_info.data.stream_info.sample_rate = x;
+	used_bits += bits;
+
+	bits = FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN;
+	if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN, read_callback_, decoder))
+		return false; /* the read_callback_ sets the state for us */
+	decoder->private_->stream_info.data.stream_info.channels = x+1;
+	used_bits += bits;
+
+	bits = FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN;
+	if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN, read_callback_, decoder))
+		return false; /* the read_callback_ sets the state for us */
+	decoder->private_->stream_info.data.stream_info.bits_per_sample = x+1;
+	used_bits += bits;
+
+	bits = FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN;
+	if(!FLAC__bitbuffer_read_raw_uint64(decoder->private_->input, &decoder->private_->stream_info.data.stream_info.total_samples, FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN, read_callback_, decoder))
+		return false; /* the read_callback_ sets the state for us */
+	used_bits += bits;
+
+	if(!FLAC__bitbuffer_read_byte_block_aligned_no_crc(decoder->private_->input, decoder->private_->stream_info.data.stream_info.md5sum, 16, read_callback_, decoder))
+		return false; /* the read_callback_ sets the state for us */
+	used_bits += 16*8;
+
+	/* skip the rest of the block */
+	FLAC__ASSERT(used_bits % 8 == 0);
+	length -= (used_bits / 8);
+	if(!FLAC__bitbuffer_read_byte_block_aligned_no_crc(decoder->private_->input, 0, length, read_callback_, decoder))
+		return false; /* the read_callback_ sets the state for us */
+
+	return true;
+}
+
+FLAC__bool read_metadata_seektable_(FLAC__StreamDecoder *decoder, FLAC__bool is_last, unsigned length)
+{
+	FLAC__uint32 i, x;
+	FLAC__uint64 xx;
+
+	FLAC__ASSERT(FLAC__bitbuffer_is_consumed_byte_aligned(decoder->private_->input));
+
+	decoder->private_->seek_table.type = FLAC__METADATA_TYPE_SEEKTABLE;
+	decoder->private_->seek_table.is_last = is_last;
+	decoder->private_->seek_table.length = length;
+
+	decoder->private_->seek_table.data.seek_table.num_points = length / FLAC__STREAM_METADATA_SEEKPOINT_LENGTH;
+
+	/* use realloc since we may pass through here several times (e.g. after seeking) */
+	if(0 == (decoder->private_->seek_table.data.seek_table.points = (FLAC__StreamMetadata_SeekPoint*)realloc(decoder->private_->seek_table.data.seek_table.points, decoder->private_->seek_table.data.seek_table.num_points * sizeof(FLAC__StreamMetadata_SeekPoint)))) {
+		decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+		return false;
+	}
+	for(i = 0; i < decoder->private_->seek_table.data.seek_table.num_points; i++) {
+		if(!FLAC__bitbuffer_read_raw_uint64(decoder->private_->input, &xx, FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN, read_callback_, decoder))
+			return false; /* the read_callback_ sets the state for us */
+		decoder->private_->seek_table.data.seek_table.points[i].sample_number = xx;
+
+		if(!FLAC__bitbuffer_read_raw_uint64(decoder->private_->input, &xx, FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN, read_callback_, decoder))
+			return false; /* the read_callback_ sets the state for us */
+		decoder->private_->seek_table.data.seek_table.points[i].stream_offset = xx;
+
+		if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN, read_callback_, decoder))
+			return false; /* the read_callback_ sets the state for us */
+		decoder->private_->seek_table.data.seek_table.points[i].frame_samples = x;
+	}
+	length -= (decoder->private_->seek_table.data.seek_table.num_points * FLAC__STREAM_METADATA_SEEKPOINT_LENGTH);
+	/* if there is a partial point left, skip over it */
+	if(length > 0) {
+		/*@@@ do an error_callback() here?  there's an argument for either way */
+		if(!FLAC__bitbuffer_read_byte_block_aligned_no_crc(decoder->private_->input, 0, length, read_callback_, decoder))
+			return false; /* the read_callback_ sets the state for us */
+	}
+
+	return true;
+}
+
+FLAC__bool read_metadata_vorbiscomment_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_VorbisComment *obj)
+{
+	FLAC__uint32 i;
+
+	FLAC__ASSERT(FLAC__bitbuffer_is_consumed_byte_aligned(decoder->private_->input));
+
+	/* read vendor string */
+	FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN == 32);
+	if(!FLAC__bitbuffer_read_raw_uint32_little_endian(decoder->private_->input, &obj->vendor_string.length, read_callback_, decoder))
+		return false; /* the read_callback_ sets the state for us */
+	if(obj->vendor_string.length > 0) {
+		if(0 == (obj->vendor_string.entry = (FLAC__byte*)malloc(obj->vendor_string.length))) {
+			decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+			return false;
+		}
+		if(!FLAC__bitbuffer_read_byte_block_aligned_no_crc(decoder->private_->input, obj->vendor_string.entry, obj->vendor_string.length, read_callback_, decoder))
+			return false; /* the read_callback_ sets the state for us */
+	}
+	else
+		obj->vendor_string.entry = 0;
+
+	/* read num comments */
+	FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN == 32);
+	if(!FLAC__bitbuffer_read_raw_uint32_little_endian(decoder->private_->input, &obj->num_comments, read_callback_, decoder))
+		return false; /* the read_callback_ sets the state for us */
+
+	/* read comments */
+	if(obj->num_comments > 0) {
+		if(0 == (obj->comments = (FLAC__StreamMetadata_VorbisComment_Entry*)malloc(obj->num_comments * sizeof(FLAC__StreamMetadata_VorbisComment_Entry)))) {
+			decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+			return false;
+		}
+		for(i = 0; i < obj->num_comments; i++) {
+			FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN == 32);
+			if(!FLAC__bitbuffer_read_raw_uint32_little_endian(decoder->private_->input, &obj->comments[i].length, read_callback_, decoder))
+				return false; /* the read_callback_ sets the state for us */
+			if(obj->comments[i].length > 0) {
+				if(0 == (obj->comments[i].entry = (FLAC__byte*)malloc(obj->comments[i].length))) {
+					decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+					return false;
+				}
+				if(!FLAC__bitbuffer_read_byte_block_aligned_no_crc(decoder->private_->input, obj->comments[i].entry, obj->comments[i].length, read_callback_, decoder))
+					return false; /* the read_callback_ sets the state for us */
+			}
+			else
+				obj->comments[i].entry = 0;
+		}
+	}
+	else {
+		obj->comments = 0;
+	}
+
+	return true;
+}
+
+FLAC__bool read_metadata_cuesheet_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_CueSheet *obj)
+{
+	FLAC__uint32 i, j, x;
+
+	FLAC__ASSERT(FLAC__bitbuffer_is_consumed_byte_aligned(decoder->private_->input));
+
+	memset(obj, 0, sizeof(FLAC__StreamMetadata_CueSheet));
+
+	FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN % 8 == 0);
+	if(!FLAC__bitbuffer_read_byte_block_aligned_no_crc(decoder->private_->input, (FLAC__byte*)obj->media_catalog_number, FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN/8, read_callback_, decoder))
+		return false; /* the read_callback_ sets the state for us */
+
+	if(!FLAC__bitbuffer_read_raw_uint64(decoder->private_->input, &obj->lead_in, FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN, read_callback_, decoder))
+		return false; /* the read_callback_ sets the state for us */
+
+	if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN, read_callback_, decoder))
+		return false; /* the read_callback_ sets the state for us */
+	obj->is_cd = x? true : false;
+
+	if(!FLAC__bitbuffer_skip_bits_no_crc(decoder->private_->input, FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN, read_callback_, decoder))
+		return false; /* the read_callback_ sets the state for us */
+
+	if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN, read_callback_, decoder))
+		return false; /* the read_callback_ sets the state for us */
+	obj->num_tracks = x;
+
+	if(obj->num_tracks > 0) {
+		if(0 == (obj->tracks = (FLAC__StreamMetadata_CueSheet_Track*)calloc(obj->num_tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track)))) {
+			decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+			return false;
+		}
+		for(i = 0; i < obj->num_tracks; i++) {
+			FLAC__StreamMetadata_CueSheet_Track *track = &obj->tracks[i];
+			if(!FLAC__bitbuffer_read_raw_uint64(decoder->private_->input, &track->offset, FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN, read_callback_, decoder))
+				return false; /* the read_callback_ sets the state for us */
+
+			if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN, read_callback_, decoder))
+				return false; /* the read_callback_ sets the state for us */
+			track->number = (FLAC__byte)x;
+
+			FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN % 8 == 0);
+			if(!FLAC__bitbuffer_read_byte_block_aligned_no_crc(decoder->private_->input, (FLAC__byte*)track->isrc, FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN/8, read_callback_, decoder))
+				return false; /* the read_callback_ sets the state for us */
+
+			if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN, read_callback_, decoder))
+				return false; /* the read_callback_ sets the state for us */
+			track->type = x;
+
+			if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN, read_callback_, decoder))
+				return false; /* the read_callback_ sets the state for us */
+			track->pre_emphasis = x;
+
+			if(!FLAC__bitbuffer_skip_bits_no_crc(decoder->private_->input, FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN, read_callback_, decoder))
+				return false; /* the read_callback_ sets the state for us */
+
+			if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN, read_callback_, decoder))
+				return false; /* the read_callback_ sets the state for us */
+			track->num_indices = (FLAC__byte)x;
+
+			if(track->num_indices > 0) {
+				if(0 == (track->indices = (FLAC__StreamMetadata_CueSheet_Index*)calloc(track->num_indices, sizeof(FLAC__StreamMetadata_CueSheet_Index)))) {
+					decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+					return false;
+				}
+				for(j = 0; j < track->num_indices; j++) {
+					FLAC__StreamMetadata_CueSheet_Index *index = &track->indices[j];
+					if(!FLAC__bitbuffer_read_raw_uint64(decoder->private_->input, &index->offset, FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN, read_callback_, decoder))
+						return false; /* the read_callback_ sets the state for us */
+
+					if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN, read_callback_, decoder))
+						return false; /* the read_callback_ sets the state for us */
+					index->number = (FLAC__byte)x;
+
+					if(!FLAC__bitbuffer_skip_bits_no_crc(decoder->private_->input, FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN, read_callback_, decoder))
+						return false; /* the read_callback_ sets the state for us */
+				}
+			}
+		}
+	}
+
+	return true;
+}
+
+FLAC__bool skip_id3v2_tag_(FLAC__StreamDecoder *decoder)
+{
+	FLAC__uint32 x;
+	unsigned i, skip;
+
+	/* skip the version and flags bytes */
+	if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->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->private_->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 */
+	if(!FLAC__bitbuffer_read_byte_block_aligned_no_crc(decoder->private_->input, 0, skip, read_callback_, decoder))
+		return false; /* the read_callback_ sets the state for us */
+	return true;
+}
+
+FLAC__bool frame_sync_(FLAC__StreamDecoder *decoder)
+{
+	FLAC__uint32 x;
+	FLAC__bool first = true;
+
+	/* 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->private_->has_stream_info && decoder->private_->stream_info.data.stream_info.total_samples) {
+		if(decoder->private_->samples_decoded >= decoder->private_->stream_info.data.stream_info.total_samples) {
+			decoder->protected_->state = FLAC__STREAM_DECODER_END_OF_STREAM;
+			return true;
+		}
+	}
+
+	/* make sure we're byte aligned */
+	if(!FLAC__bitbuffer_is_consumed_byte_aligned(decoder->private_->input)) {
+		if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, FLAC__bitbuffer_bits_left_for_byte_alignment(decoder->private_->input), read_callback_, decoder))
+			return false; /* the read_callback_ sets the state for us */
+	}
+
+	while(1) {
+		if(decoder->private_->cached) {
+			x = (FLAC__uint32)decoder->private_->lookahead;
+			decoder->private_->cached = false;
+		}
+		else {
+			if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->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 */
+			decoder->private_->header_warmup[0] = (FLAC__byte)x;
+			if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, 8, read_callback_, decoder))
+				return false; /* the read_callback_ sets the state for us */
+
+			/* we have to check if we just read two 0xff's in a row; the second may actually be the beginning of the sync code */
+			/* else we have to check if the second byte is the end of a sync code */
+			if(x == 0xff) { /* MAGIC NUMBER for the first 8 frame sync bits */
+				decoder->private_->lookahead = (FLAC__byte)x;
+				decoder->private_->cached = true;
+			}
+			else if(x >> 2 == 0x3e) { /* MAGIC NUMBER for the last 6 sync bits */
+				decoder->private_->header_warmup[1] = (FLAC__byte)x;
+				decoder->protected_->state = FLAC__STREAM_DECODER_READ_FRAME;
+				return true;
+			}
+		}
+		if(first) {
+			decoder->private_->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC, decoder->private_->client_data);
+			first = false;
+		}
+	}
+
+	return true;
+}
+
+FLAC__bool read_frame_(FLAC__StreamDecoder *decoder, FLAC__bool *got_a_frame, FLAC__bool do_full_decode)
+{
+	unsigned channel;
+	unsigned i;
+	FLAC__int32 mid, side, left, right;
+	FLAC__uint16 frame_crc; /* the one we calculate from the input stream */
+	FLAC__uint32 x;
+
+	*got_a_frame = false;
+
+	/* init the CRC */
+	frame_crc = 0;
+	FLAC__CRC16_UPDATE(decoder->private_->header_warmup[0], frame_crc);
+	FLAC__CRC16_UPDATE(decoder->private_->header_warmup[1], frame_crc);
+	FLAC__bitbuffer_reset_read_crc16(decoder->private_->input, frame_crc);
+
+	if(!read_frame_header_(decoder))
+		return false;
+	if(decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC)
+		return true;
+	if(!allocate_output_(decoder, decoder->private_->frame.header.blocksize, decoder->private_->frame.header.channels))
+		return false;
+	for(channel = 0; channel < decoder->private_->frame.header.channels; channel++) {
+		/*
+		 * first figure the correct bits-per-sample of the subframe
+		 */
+		unsigned bps = decoder->private_->frame.header.bits_per_sample;
+		switch(decoder->private_->frame.header.channel_assignment) {
+			case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT:
+				/* no adjustment needed */
+				break;
+			case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE:
+				FLAC__ASSERT(decoder->private_->frame.header.channels == 2);
+				if(channel == 1)
+					bps++;
+				break;
+			case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE:
+				FLAC__ASSERT(decoder->private_->frame.header.channels == 2);
+				if(channel == 0)
+					bps++;
+				break;
+			case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE:
+				FLAC__ASSERT(decoder->private_->frame.header.channels == 2);
+				if(channel == 1)
+					bps++;
+				break;
+			default:
+				FLAC__ASSERT(0);
+		}
+		/*
+		 * now read it
+		 */
+		if(!read_subframe_(decoder, channel, bps, do_full_decode))
+			return false;
+		if(decoder->protected_->state != FLAC__STREAM_DECODER_READ_FRAME) {
+			decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+			return true;
+		}
+	}
+	if(!read_zero_padding_(decoder))
+		return false;
+
+	/*
+	 * Read the frame CRC-16 from the footer and check
+	 */
+	frame_crc = FLAC__bitbuffer_get_read_crc16(decoder->private_->input);
+	if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, FLAC__FRAME_FOOTER_CRC_LEN, read_callback_, decoder))
+		return false; /* the read_callback_ sets the state for us */
+	if(frame_crc == (FLAC__uint16)x) {
+		if(do_full_decode) {
+			/* Undo any special channel coding */
+			switch(decoder->private_->frame.header.channel_assignment) {
+				case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT:
+					/* do nothing */
+					break;
+				case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE:
+					FLAC__ASSERT(decoder->private_->frame.header.channels == 2);
+					for(i = 0; i < decoder->private_->frame.header.blocksize; i++)
+						decoder->private_->output[1][i] = decoder->private_->output[0][i] - decoder->private_->output[1][i];
+					break;
+				case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE:
+					FLAC__ASSERT(decoder->private_->frame.header.channels == 2);
+					for(i = 0; i < decoder->private_->frame.header.blocksize; i++)
+						decoder->private_->output[0][i] += decoder->private_->output[1][i];
+					break;
+				case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE:
+					FLAC__ASSERT(decoder->private_->frame.header.channels == 2);
+					for(i = 0; i < decoder->private_->frame.header.blocksize; i++) {
+						mid = decoder->private_->output[0][i];
+						side = decoder->private_->output[1][i];
+						mid <<= 1;
+						if(side & 1) /* i.e. if 'side' is odd... */
+							mid++;
+						left = mid + side;
+						right = mid - side;
+						decoder->private_->output[0][i] = left >> 1;
+						decoder->private_->output[1][i] = right >> 1;
+					}
+					break;
+				default:
+					FLAC__ASSERT(0);
+					break;
+			}
+		}
+	}
+	else {
+		/* Bad frame, emit error and zero the output signal */
+		decoder->private_->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH, decoder->private_->client_data);
+		if(do_full_decode) {
+			for(channel = 0; channel < decoder->private_->frame.header.channels; channel++) {
+				memset(decoder->private_->output[channel], 0, sizeof(FLAC__int32) * decoder->private_->frame.header.blocksize);
+			}
+		}
+	}
+
+	*got_a_frame = true;
+
+	/* put the latest values into the public section of the decoder instance */
+	decoder->protected_->channels = decoder->private_->frame.header.channels;
+	decoder->protected_->channel_assignment = decoder->private_->frame.header.channel_assignment;
+	decoder->protected_->bits_per_sample = decoder->private_->frame.header.bits_per_sample;
+	decoder->protected_->sample_rate = decoder->private_->frame.header.sample_rate;
+	decoder->protected_->blocksize = decoder->private_->frame.header.blocksize;
+
+	FLAC__ASSERT(decoder->private_->frame.header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER);
+	decoder->private_->samples_decoded = decoder->private_->frame.header.number.sample_number + decoder->private_->frame.header.blocksize;
+
+	/* write it */
+	if(do_full_decode) {
+		if(decoder->private_->write_callback(decoder, &decoder->private_->frame, (const FLAC__int32 * const *)decoder->private_->output, decoder->private_->client_data) != FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE)
+			return false;
+	}
+
+	decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+	return true;
+}
+
+FLAC__bool read_frame_header_(FLAC__StreamDecoder *decoder)
+{
+	FLAC__uint32 x;
+	FLAC__uint64 xx;
+	unsigned i, blocksize_hint = 0, sample_rate_hint = 0;
+	FLAC__byte crc8, raw_header[16]; /* MAGIC NUMBER based on the maximum frame header size, including CRC */
+	unsigned raw_header_len;
+	FLAC__bool is_unparseable = false;
+	const FLAC__bool is_known_variable_blocksize_stream = (decoder->private_->has_stream_info && decoder->private_->stream_info.data.stream_info.min_blocksize != decoder->private_->stream_info.data.stream_info.max_blocksize);
+	const FLAC__bool is_known_fixed_blocksize_stream = (decoder->private_->has_stream_info && decoder->private_->stream_info.data.stream_info.min_blocksize == decoder->private_->stream_info.data.stream_info.max_blocksize);
+
+	FLAC__ASSERT(FLAC__bitbuffer_is_consumed_byte_aligned(decoder->private_->input));
+
+	/* init the raw header with the saved bits from synchronization */
+	raw_header[0] = decoder->private_->header_warmup[0];
+	raw_header[1] = decoder->private_->header_warmup[1];
+	raw_header_len = 2;
+
+	/*
+	 * check to make sure that the reserved bits are 0
+	 */
+	if(raw_header[1] & 0x03) { /* MAGIC NUMBER */
+		is_unparseable = true;
+	}
+
+	/*
+	 * Note that along the way as we read the header, we look for a sync
+	 * code inside.  If we find one it would indicate that our original
+	 * sync was bad since there cannot be a sync code in a valid header.
+	 */
+
+	/*
+	 * 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->private_->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 */
+			/* if we get here it means our original sync was erroneous since the sync code cannot appear in the header */
+			decoder->private_->lookahead = (FLAC__byte)x;
+			decoder->private_->cached = true;
+			decoder->private_->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER, decoder->private_->client_data);
+			decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+			return true;
+		}
+		raw_header[raw_header_len++] = (FLAC__byte)x;
+	}
+
+	switch(x = raw_header[2] >> 4) {
+		case 0:
+			if(is_known_fixed_blocksize_stream)
+				decoder->private_->frame.header.blocksize = decoder->private_->stream_info.data.stream_info.min_blocksize;
+			else
+				is_unparseable = true;
+			break;
+		case 1:
+			decoder->private_->frame.header.blocksize = 192;
+			break;
+		case 2:
+		case 3:
+		case 4:
+		case 5:
+			decoder->private_->frame.header.blocksize = 576 << (x-2);
+			break;
+		case 6:
+		case 7:
+			blocksize_hint = x;
+			break;
+		case 8:
+		case 9:
+		case 10:
+		case 11:
+		case 12:
+		case 13:
+		case 14:
+		case 15:
+			decoder->private_->frame.header.blocksize = 256 << (x-8);
+			break;
+		default:
+			FLAC__ASSERT(0);
+			break;
+	}
+
+	switch(x = raw_header[2] & 0x0f) {
+		case 0:
+			if(decoder->private_->has_stream_info)
+				decoder->private_->frame.header.sample_rate = decoder->private_->stream_info.data.stream_info.sample_rate;
+			else
+				is_unparseable = true;
+			break;
+		case 1:
+		case 2:
+		case 3:
+			is_unparseable = true;
+			break;
+		case 4:
+			decoder->private_->frame.header.sample_rate = 8000;
+			break;
+		case 5:
+			decoder->private_->frame.header.sample_rate = 16000;
+			break;
+		case 6:
+			decoder->private_->frame.header.sample_rate = 22050;
+			break;
+		case 7:
+			decoder->private_->frame.header.sample_rate = 24000;
+			break;
+		case 8:
+			decoder->private_->frame.header.sample_rate = 32000;
+			break;
+		case 9:
+			decoder->private_->frame.header.sample_rate = 44100;
+			break;
+		case 10:
+			decoder->private_->frame.header.sample_rate = 48000;
+			break;
+		case 11:
+			decoder->private_->frame.header.sample_rate = 96000;
+			break;
+		case 12:
+		case 13:
+		case 14:
+			sample_rate_hint = x;
+			break;
+		case 15:
+			decoder->private_->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER, decoder->private_->client_data);
+			decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+			return true;
+		default:
+			FLAC__ASSERT(0);
+	}
+
+	x = (unsigned)(raw_header[3] >> 4);
+	if(x & 8) {
+		decoder->private_->frame.header.channels = 2;
+		switch(x & 7) {
+			case 0:
+				decoder->private_->frame.header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE;
+				break;
+			case 1:
+				decoder->private_->frame.header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE;
+				break;
+			case 2:
+				decoder->private_->frame.header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_MID_SIDE;
+				break;
+			default:
+				is_unparseable = true;
+				break;
+		}
+	}
+	else {
+		decoder->private_->frame.header.channels = (unsigned)x + 1;
+		decoder->private_->frame.header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT;
+	}
+
+	switch(x = (unsigned)(raw_header[3] & 0x0e) >> 1) {
+		case 0:
+			if(decoder->private_->has_stream_info)
+				decoder->private_->frame.header.bits_per_sample = decoder->private_->stream_info.data.stream_info.bits_per_sample;
+			else
+				is_unparseable = true;
+			break;
+		case 1:
+			decoder->private_->frame.header.bits_per_sample = 8;
+			break;
+		case 2:
+			decoder->private_->frame.header.bits_per_sample = 12;
+			break;
+		case 4:
+			decoder->private_->frame.header.bits_per_sample = 16;
+			break;
+		case 5:
+			decoder->private_->frame.header.bits_per_sample = 20;
+			break;
+		case 6:
+			decoder->private_->frame.header.bits_per_sample = 24;
+			break;
+		case 3:
+		case 7:
+			is_unparseable = true;
+			break;
+		default:
+			FLAC__ASSERT(0);
+			break;
+	}
+
+	if(raw_header[3] & 0x01) { /* this should be a zero padding bit */
+		decoder->private_->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER, decoder->private_->client_data);
+		decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+		return true;
+	}
+
+	if(blocksize_hint && is_known_variable_blocksize_stream) {
+		if(!FLAC__bitbuffer_read_utf8_uint64(decoder->private_->input, &xx, read_callback_, decoder, raw_header, &raw_header_len))
+			return false; /* the read_callback_ sets the state for us */
+		if(xx == FLAC__U64L(0xffffffffffffffff)) { /* i.e. non-UTF8 code... */
+			decoder->private_->lookahead = raw_header[raw_header_len-1]; /* back up as much as we can */
+			decoder->private_->cached = true;
+			decoder->private_->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER, decoder->private_->client_data);
+			decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+			return true;
+		}
+		decoder->private_->frame.header.number_type = FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER;
+		decoder->private_->frame.header.number.sample_number = xx;
+	}
+	else {
+		if(!FLAC__bitbuffer_read_utf8_uint32(decoder->private_->input, &x, read_callback_, decoder, raw_header, &raw_header_len))
+			return false; /* the read_callback_ sets the state for us */
+		if(x == 0xffffffff) { /* i.e. non-UTF8 code... */
+			decoder->private_->lookahead = raw_header[raw_header_len-1]; /* back up as much as we can */
+			decoder->private_->cached = true;
+			decoder->private_->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER, decoder->private_->client_data);
+			decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+			return true;
+		}
+		decoder->private_->last_frame_number = x;
+		decoder->private_->frame.header.number_type = FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER;
+		if(blocksize_hint) {
+			if(decoder->private_->has_stream_info)
+				decoder->private_->frame.header.number.sample_number = (FLAC__int64)decoder->private_->stream_info.data.stream_info.min_blocksize * (FLAC__int64)x;
+			else
+				is_unparseable = true;
+		}
+		else	
+			decoder->private_->frame.header.number.sample_number = (FLAC__int64)decoder->private_->frame.header.blocksize * (FLAC__int64)x;
+	}
+
+	if(blocksize_hint) {
+		if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, 8, read_callback_, decoder))
+			return false; /* the read_callback_ sets the state for us */
+		raw_header[raw_header_len++] = (FLAC__byte)x;
+		if(blocksize_hint == 7) {
+			FLAC__uint32 _x;
+			if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &_x, 8, read_callback_, decoder))
+				return false; /* the read_callback_ sets the state for us */
+			raw_header[raw_header_len++] = (FLAC__byte)_x;
+			x = (x << 8) | _x;
+		}
+		decoder->private_->frame.header.blocksize = x+1;
+	}
+
+	if(sample_rate_hint) {
+		if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, 8, read_callback_, decoder))
+			return false; /* the read_callback_ sets the state for us */
+		raw_header[raw_header_len++] = (FLAC__byte)x;
+		if(sample_rate_hint != 12) {
+			FLAC__uint32 _x;
+			if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &_x, 8, read_callback_, decoder))
+				return false; /* the read_callback_ sets the state for us */
+			raw_header[raw_header_len++] = (FLAC__byte)_x;
+			x = (x << 8) | _x;
+		}
+		if(sample_rate_hint == 12)
+			decoder->private_->frame.header.sample_rate = x*1000;
+		else if(sample_rate_hint == 13)
+			decoder->private_->frame.header.sample_rate = x;
+		else
+			decoder->private_->frame.header.sample_rate = x*10;
+	}
+
+	/* read the CRC-8 byte */
+	if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, 8, read_callback_, decoder))
+		return false; /* the read_callback_ sets the state for us */
+	crc8 = (FLAC__byte)x;
+
+	if(FLAC__crc8(raw_header, raw_header_len) != crc8) {
+		decoder->private_->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER, decoder->private_->client_data);
+		decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+		return true;
+	}
+
+	if(is_unparseable) {
+		decoder->protected_->state = FLAC__STREAM_DECODER_UNPARSEABLE_STREAM;
+		return false;
+	}
+
+	return true;
+}
+
+FLAC__bool read_subframe_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, FLAC__bool do_full_decode)
+{
+	FLAC__uint32 x;
+	FLAC__bool wasted_bits;
+
+	if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, 8, read_callback_, decoder)) /* MAGIC NUMBER */
+		return false; /* the read_callback_ sets the state for us */
+
+	wasted_bits = (x & 1);
+	x &= 0xfe;
+
+	if(wasted_bits) {
+		unsigned u;
+		if(!FLAC__bitbuffer_read_unary_unsigned(decoder->private_->input, &u, read_callback_, decoder))
+			return false; /* the read_callback_ sets the state for us */
+		decoder->private_->frame.subframes[channel].wasted_bits = u+1;
+		bps -= decoder->private_->frame.subframes[channel].wasted_bits;
+	}
+	else
+		decoder->private_->frame.subframes[channel].wasted_bits = 0;
+
+	/*
+	 * Lots of magic numbers here
+	 */
+	if(x & 0x80) {
+		decoder->private_->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC, decoder->private_->client_data);
+		decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+		return true;
+	}
+	else if(x == 0) {
+		if(!read_subframe_constant_(decoder, channel, bps, do_full_decode))
+			return false;
+	}
+	else if(x == 2) {
+		if(!read_subframe_verbatim_(decoder, channel, bps, do_full_decode))
+			return false;
+	}
+	else if(x < 16) {
+		decoder->protected_->state = FLAC__STREAM_DECODER_UNPARSEABLE_STREAM;
+		return false;
+	}
+	else if(x <= 24) {
+		if(!read_subframe_fixed_(decoder, channel, bps, (x>>1)&7, do_full_decode))
+			return false;
+	}
+	else if(x < 64) {
+		decoder->protected_->state = FLAC__STREAM_DECODER_UNPARSEABLE_STREAM;
+		return false;
+	}
+	else {
+		if(!read_subframe_lpc_(decoder, channel, bps, ((x>>1)&31)+1, do_full_decode))
+			return false;
+	}
+
+	if(wasted_bits && do_full_decode) {
+		unsigned i;
+		x = decoder->private_->frame.subframes[channel].wasted_bits;
+		for(i = 0; i < decoder->private_->frame.header.blocksize; i++)
+			decoder->private_->output[channel][i] <<= x;
+	}
+
+	return true;
+}
+
+FLAC__bool read_subframe_constant_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, FLAC__bool do_full_decode)
+{
+	FLAC__Subframe_Constant *subframe = &decoder->private_->frame.subframes[channel].data.constant;
+	FLAC__int32 x;
+	unsigned i;
+	FLAC__int32 *output = decoder->private_->output[channel];
+
+	decoder->private_->frame.subframes[channel].type = FLAC__SUBFRAME_TYPE_CONSTANT;
+
+	if(!FLAC__bitbuffer_read_raw_int32(decoder->private_->input, &x, bps, read_callback_, decoder))
+		return false; /* the read_callback_ sets the state for us */
+
+	subframe->value = x;
+
+	/* decode the subframe */
+	if(do_full_decode) {
+		for(i = 0; i < decoder->private_->frame.header.blocksize; i++)
+			output[i] = x;
+	}
+
+	return true;
+}
+
+FLAC__bool read_subframe_fixed_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, const unsigned order, FLAC__bool do_full_decode)
+{
+	FLAC__Subframe_Fixed *subframe = &decoder->private_->frame.subframes[channel].data.fixed;
+	FLAC__int32 i32;
+	FLAC__uint32 u32;
+	unsigned u;
+
+	decoder->private_->frame.subframes[channel].type = FLAC__SUBFRAME_TYPE_FIXED;
+
+	subframe->residual = decoder->private_->residual[channel];
+	subframe->order = order;
+
+	/* read warm-up samples */
+	for(u = 0; u < order; u++) {
+		if(!FLAC__bitbuffer_read_raw_int32(decoder->private_->input, &i32, bps, read_callback_, decoder))
+			return false; /* the read_callback_ sets the state for us */
+		subframe->warmup[u] = i32;
+	}
+
+	/* read entropy coding method info */
+	if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &u32, FLAC__ENTROPY_CODING_METHOD_TYPE_LEN, read_callback_, decoder))
+		return false; /* the read_callback_ sets the state for us */
+	subframe->entropy_coding_method.type = (FLAC__EntropyCodingMethodType)u32;
+	switch(subframe->entropy_coding_method.type) {
+		case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE:
+			if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &u32, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN, read_callback_, decoder))
+				return false; /* the read_callback_ sets the state for us */
+			subframe->entropy_coding_method.data.partitioned_rice.order = u32;
+			subframe->entropy_coding_method.data.partitioned_rice.contents = &decoder->private_->partitioned_rice_contents[channel];
+			break;
+		default:
+			decoder->protected_->state = FLAC__STREAM_DECODER_UNPARSEABLE_STREAM;
+			return false;
+	}
+
+	/* read residual */
+	switch(subframe->entropy_coding_method.type) {
+		case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE:
+			if(!read_residual_partitioned_rice_(decoder, order, subframe->entropy_coding_method.data.partitioned_rice.order, &decoder->private_->partitioned_rice_contents[channel], decoder->private_->residual[channel]))
+				return false;
+			break;
+		default:
+			FLAC__ASSERT(0);
+	}
+
+	/* decode the subframe */
+	if(do_full_decode) {
+		memcpy(decoder->private_->output[channel], subframe->warmup, sizeof(FLAC__int32) * order);
+		FLAC__fixed_restore_signal(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, order, decoder->private_->output[channel]+order);
+	}
+
+	return true;
+}
+
+FLAC__bool read_subframe_lpc_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, const unsigned order, FLAC__bool do_full_decode)
+{
+	FLAC__Subframe_LPC *subframe = &decoder->private_->frame.subframes[channel].data.lpc;
+	FLAC__int32 i32;
+	FLAC__uint32 u32;
+	unsigned u;
+
+	decoder->private_->frame.subframes[channel].type = FLAC__SUBFRAME_TYPE_LPC;
+
+	subframe->residual = decoder->private_->residual[channel];
+	subframe->order = order;
+
+	/* read warm-up samples */
+	for(u = 0; u < order; u++) {
+		if(!FLAC__bitbuffer_read_raw_int32(decoder->private_->input, &i32, bps, read_callback_, decoder))
+			return false; /* the read_callback_ sets the state for us */
+		subframe->warmup[u] = i32;
+	}
+
+	/* read qlp coeff precision */
+	if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &u32, FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN, read_callback_, decoder))
+		return false; /* the read_callback_ sets the state for us */
+	if(u32 == (1u << FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN) - 1) {
+		decoder->private_->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC, decoder->private_->client_data);
+		decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+		return true;
+	}
+	subframe->qlp_coeff_precision = u32+1;
+
+	/* read qlp shift */
+	if(!FLAC__bitbuffer_read_raw_int32(decoder->private_->input, &i32, FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN, read_callback_, decoder))
+		return false; /* the read_callback_ sets the state for us */
+	subframe->quantization_level = i32;
+
+	/* read quantized lp coefficiencts */
+	for(u = 0; u < order; u++) {
+		if(!FLAC__bitbuffer_read_raw_int32(decoder->private_->input, &i32, subframe->qlp_coeff_precision, read_callback_, decoder))
+			return false; /* the read_callback_ sets the state for us */
+		subframe->qlp_coeff[u] = i32;
+	}
+
+	/* read entropy coding method info */
+	if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &u32, FLAC__ENTROPY_CODING_METHOD_TYPE_LEN, read_callback_, decoder))
+		return false; /* the read_callback_ sets the state for us */
+	subframe->entropy_coding_method.type = (FLAC__EntropyCodingMethodType)u32;
+	switch(subframe->entropy_coding_method.type) {
+		case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE:
+			if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &u32, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN, read_callback_, decoder))
+				return false; /* the read_callback_ sets the state for us */
+			subframe->entropy_coding_method.data.partitioned_rice.order = u32;
+			subframe->entropy_coding_method.data.partitioned_rice.contents = &decoder->private_->partitioned_rice_contents[channel];
+			break;
+		default:
+			decoder->protected_->state = FLAC__STREAM_DECODER_UNPARSEABLE_STREAM;
+			return false;
+	}
+
+	/* read residual */
+	switch(subframe->entropy_coding_method.type) {
+		case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE:
+			if(!read_residual_partitioned_rice_(decoder, order, subframe->entropy_coding_method.data.partitioned_rice.order, &decoder->private_->partitioned_rice_contents[channel], decoder->private_->residual[channel]))
+				return false;
+			break;
+		default:
+			FLAC__ASSERT(0);
+	}
+
+	/* decode the subframe */
+	if(do_full_decode) {
+		memcpy(decoder->private_->output[channel], subframe->warmup, sizeof(FLAC__int32) * order);
+		if(bps + subframe->qlp_coeff_precision + FLAC__bitmath_ilog2(order) <= 32)
+			if(bps <= 16 && subframe->qlp_coeff_precision <= 16) {
+				if(order <= 8)
+					decoder->private_->local_lpc_restore_signal_16bit_order8(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, subframe->qlp_coeff, order, subframe->quantization_level, decoder->private_->output[channel]+order);
+				else
+					decoder->private_->local_lpc_restore_signal_16bit(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, subframe->qlp_coeff, order, subframe->quantization_level, decoder->private_->output[channel]+order);
+			}
+			else
+				decoder->private_->local_lpc_restore_signal(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, subframe->qlp_coeff, order, subframe->quantization_level, decoder->private_->output[channel]+order);
+		else
+			decoder->private_->local_lpc_restore_signal_64bit(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, subframe->qlp_coeff, order, subframe->quantization_level, decoder->private_->output[channel]+order);
+	}
+
+	return true;
+}
+
+FLAC__bool read_subframe_verbatim_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, FLAC__bool do_full_decode)
+{
+	FLAC__Subframe_Verbatim *subframe = &decoder->private_->frame.subframes[channel].data.verbatim;
+	FLAC__int32 x, *residual = decoder->private_->residual[channel];
+	unsigned i;
+
+	decoder->private_->frame.subframes[channel].type = FLAC__SUBFRAME_TYPE_VERBATIM;
+
+	subframe->data = residual;
+
+	for(i = 0; i < decoder->private_->frame.header.blocksize; i++) {
+		if(!FLAC__bitbuffer_read_raw_int32(decoder->private_->input, &x, bps, read_callback_, decoder))
+			return false; /* the read_callback_ sets the state for us */
+		residual[i] = x;
+	}
+
+	/* decode the subframe */
+	if(do_full_decode)
+		memcpy(decoder->private_->output[channel], subframe->data, sizeof(FLAC__int32) * decoder->private_->frame.header.blocksize);
+
+	return true;
+}
+
+FLAC__bool read_residual_partitioned_rice_(FLAC__StreamDecoder *decoder, unsigned predictor_order, unsigned partition_order, FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents, FLAC__int32 *residual)
+{
+	FLAC__uint32 rice_parameter;
+	int i;
+	unsigned partition, sample, u;
+	const unsigned partitions = 1u << partition_order;
+	const unsigned partition_samples = partition_order > 0? decoder->private_->frame.header.blocksize >> partition_order : decoder->private_->frame.header.blocksize - predictor_order;
+
+	if(!FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(partitioned_rice_contents, max(6, partition_order))) {
+		decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+		return false;
+	}
+
+	sample = 0;
+	for(partition = 0; partition < partitions; partition++) {
+		if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &rice_parameter, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN, read_callback_, decoder))
+			return false; /* the read_callback_ sets the state for us */
+		partitioned_rice_contents->parameters[partition] = rice_parameter;
+		if(rice_parameter < FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER) {
+#ifdef FLAC__SYMMETRIC_RICE
+			for(u = (partition_order == 0 || partition > 0)? 0 : predictor_order; u < partition_samples; u++, sample++) {
+				if(!FLAC__bitbuffer_read_symmetric_rice_signed(decoder->private_->input, &i, rice_parameter, read_callback_, decoder))
+					return false; /* the read_callback_ sets the state for us */
+				residual[sample] = i;
+			}
+#else
+			u = (partition_order == 0 || partition > 0)? partition_samples : partition_samples - predictor_order;
+			if(!FLAC__bitbuffer_read_rice_signed_block(decoder->private_->input, residual + sample, u, rice_parameter, read_callback_, decoder))
+				return false; /* the read_callback_ sets the state for us */
+			sample += u;
+#endif
+		}
+		else {
+			if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &rice_parameter, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN, read_callback_, decoder))
+				return false; /* the read_callback_ sets the state for us */
+			partitioned_rice_contents->raw_bits[partition] = rice_parameter;
+			for(u = (partition_order == 0 || partition > 0)? 0 : predictor_order; u < partition_samples; u++, sample++) {
+				if(!FLAC__bitbuffer_read_raw_int32(decoder->private_->input, &i, rice_parameter, read_callback_, decoder))
+					return false; /* the read_callback_ sets the state for us */
+				residual[sample] = i;
+			}
+		}
+	}
+
+	return true;
+}
+
+FLAC__bool read_zero_padding_(FLAC__StreamDecoder *decoder)
+{
+	if(!FLAC__bitbuffer_is_consumed_byte_aligned(decoder->private_->input)) {
+		FLAC__uint32 zero = 0;
+		if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &zero, FLAC__bitbuffer_bits_left_for_byte_alignment(decoder->private_->input), read_callback_, decoder))
+			return false; /* the read_callback_ sets the state for us */
+		if(zero != 0) {
+			decoder->private_->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC, decoder->private_->client_data);
+			decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+		}
+	}
+	return true;
+}
+
+FLAC__bool read_callback_(FLAC__byte buffer[], unsigned *bytes, void *client_data)
+{
+	FLAC__StreamDecoder *decoder = (FLAC__StreamDecoder *)client_data;
+	FLAC__StreamDecoderReadStatus status;
+
+	status = decoder->private_->read_callback(decoder, buffer, bytes, decoder->private_->client_data);
+	if(status == FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM)
+		decoder->protected_->state = FLAC__STREAM_DECODER_END_OF_STREAM;
+	else if(status == FLAC__STREAM_DECODER_READ_STATUS_ABORT)
+		decoder->protected_->state = FLAC__STREAM_DECODER_ABORTED;
+	return status == FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+}
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/stream_encoder.c
@@ -1,0 +1,3161 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h> /* for malloc() */
+#include <string.h> /* for memcpy() */
+#include "FLAC/assert.h"
+#include "FLAC/stream_decoder.h"
+#include "protected/stream_encoder.h"
+#include "private/bitbuffer.h"
+#include "private/bitmath.h"
+#include "private/crc.h"
+#include "private/cpu.h"
+#include "private/fixed.h"
+#include "private/format.h"
+#include "private/lpc.h"
+#include "private/md5.h"
+#include "private/memory.h"
+#include "private/stream_encoder_framing.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#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))
+
+typedef struct {
+	FLAC__int32 *data[FLAC__MAX_CHANNELS];
+	unsigned size; /* of each data[] in samples */
+	unsigned tail;
+} verify_input_fifo;
+
+typedef struct {
+	const FLAC__byte *data;
+	unsigned capacity;
+	unsigned bytes;
+} verify_output;
+
+typedef enum {
+	ENCODER_IN_MAGIC = 0,
+	ENCODER_IN_METADATA = 1,
+	ENCODER_IN_AUDIO = 2
+} EncoderStateHint;
+
+/***********************************************************************
+ *
+ * Private class method prototypes
+ *
+ ***********************************************************************/
+
+static void set_defaults_(FLAC__StreamEncoder *encoder);
+static void free_(FLAC__StreamEncoder *encoder);
+static FLAC__bool resize_buffers_(FLAC__StreamEncoder *encoder, unsigned new_size);
+static FLAC__bool write_bitbuffer_(FLAC__StreamEncoder *encoder, unsigned samples);
+static FLAC__bool process_frame_(FLAC__StreamEncoder *encoder, FLAC__bool is_last_frame);
+static FLAC__bool process_subframes_(FLAC__StreamEncoder *encoder, FLAC__bool is_last_frame);
+
+static FLAC__bool process_subframe_(
+	FLAC__StreamEncoder *encoder,
+	unsigned min_partition_order,
+	unsigned max_partition_order,
+	FLAC__bool precompute_partition_sums,
+	const FLAC__FrameHeader *frame_header,
+	unsigned subframe_bps,
+	const FLAC__int32 integer_signal[],
+	const FLAC__real real_signal[],
+	FLAC__Subframe *subframe[2],
+	FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents[2],
+	FLAC__int32 *residual[2],
+	unsigned *best_subframe,
+	unsigned *best_bits
+);
+
+static FLAC__bool add_subframe_(
+	FLAC__StreamEncoder *encoder,
+	const FLAC__FrameHeader *frame_header,
+	unsigned subframe_bps,
+	const FLAC__Subframe *subframe,
+	FLAC__BitBuffer *frame
+);
+
+static unsigned evaluate_constant_subframe_(
+	const FLAC__int32 signal,
+	unsigned subframe_bps,
+	FLAC__Subframe *subframe
+);
+
+static unsigned evaluate_fixed_subframe_(
+	FLAC__StreamEncoder *encoder,
+	const FLAC__int32 signal[],
+	FLAC__int32 residual[],
+	FLAC__uint32 abs_residual[],
+	FLAC__uint64 abs_residual_partition_sums[],
+	unsigned raw_bits_per_partition[],
+	unsigned blocksize,
+	unsigned subframe_bps,
+	unsigned order,
+	unsigned rice_parameter,
+	unsigned min_partition_order,
+	unsigned max_partition_order,
+	FLAC__bool precompute_partition_sums,
+	FLAC__bool do_escape_coding,
+	unsigned rice_parameter_search_dist,
+	FLAC__Subframe *subframe,
+	FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents
+);
+
+static unsigned evaluate_lpc_subframe_(
+	FLAC__StreamEncoder *encoder,
+	const FLAC__int32 signal[],
+	FLAC__int32 residual[],
+	FLAC__uint32 abs_residual[],
+	FLAC__uint64 abs_residual_partition_sums[],
+	unsigned raw_bits_per_partition[],
+	const FLAC__real lp_coeff[],
+	unsigned blocksize,
+	unsigned subframe_bps,
+	unsigned order,
+	unsigned qlp_coeff_precision,
+	unsigned rice_parameter,
+	unsigned min_partition_order,
+	unsigned max_partition_order,
+	FLAC__bool precompute_partition_sums,
+	FLAC__bool do_escape_coding,
+	unsigned rice_parameter_search_dist,
+	FLAC__Subframe *subframe,
+	FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents
+);
+
+static unsigned evaluate_verbatim_subframe_(
+	const FLAC__int32 signal[],
+	unsigned blocksize,
+	unsigned subframe_bps,
+	FLAC__Subframe *subframe
+);
+
+static unsigned find_best_partition_order_(
+	struct FLAC__StreamEncoderPrivate *private_,
+	const FLAC__int32 residual[],
+	FLAC__uint32 abs_residual[],
+	FLAC__uint64 abs_residual_partition_sums[],
+	unsigned raw_bits_per_partition[],
+	unsigned residual_samples,
+	unsigned predictor_order,
+	unsigned rice_parameter,
+	unsigned min_partition_order,
+	unsigned max_partition_order,
+	FLAC__bool precompute_partition_sums,
+	FLAC__bool do_escape_coding,
+	unsigned rice_parameter_search_dist,
+	FLAC__EntropyCodingMethod_PartitionedRice *best_partitioned_rice
+);
+
+static void precompute_partition_info_sums_(
+	const FLAC__uint32 abs_residual[],
+	FLAC__uint64 abs_residual_partition_sums[],
+	unsigned residual_samples,
+	unsigned predictor_order,
+	unsigned min_partition_order,
+	unsigned max_partition_order
+);
+
+static void precompute_partition_info_escapes_(
+	const FLAC__int32 residual[],
+	unsigned raw_bits_per_partition[],
+	unsigned residual_samples,
+	unsigned predictor_order,
+	unsigned min_partition_order,
+	unsigned max_partition_order
+);
+
+#ifdef DONT_ESTIMATE_RICE_BITS
+static FLAC__bool set_partitioned_rice_(
+	const FLAC__uint32 abs_residual[],
+	const FLAC__int32 residual[],
+	const unsigned residual_samples,
+	const unsigned predictor_order,
+	const unsigned suggested_rice_parameter,
+	const unsigned rice_parameter_search_dist,
+	const unsigned partition_order,
+	FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents,
+	unsigned *bits
+);
+
+static FLAC__bool set_partitioned_rice_with_precompute_(
+	const FLAC__int32 residual[],
+	const FLAC__uint64 abs_residual_partition_sums[],
+	const unsigned raw_bits_per_partition[],
+	const unsigned residual_samples,
+	const unsigned predictor_order,
+	const unsigned suggested_rice_parameter,
+	const unsigned rice_parameter_search_dist,
+	const unsigned partition_order,
+	const FLAC__bool search_for_escapes,
+	FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents,
+	unsigned *bits
+);
+#else
+static FLAC__bool set_partitioned_rice_(
+	const FLAC__uint32 abs_residual[],
+	const unsigned residual_samples,
+	const unsigned predictor_order,
+	const unsigned suggested_rice_parameter,
+	const unsigned rice_parameter_search_dist,
+	const unsigned partition_order,
+	FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents,
+	unsigned *bits
+);
+
+static FLAC__bool set_partitioned_rice_with_precompute_(
+	const FLAC__uint32 abs_residual[],
+	const FLAC__uint64 abs_residual_partition_sums[],
+	const unsigned raw_bits_per_partition[],
+	const unsigned residual_samples,
+	const unsigned predictor_order,
+	const unsigned suggested_rice_parameter,
+	const unsigned rice_parameter_search_dist,
+	const unsigned partition_order,
+	const FLAC__bool search_for_escapes,
+	FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents,
+	unsigned *bits
+);
+#endif
+
+static unsigned get_wasted_bits_(FLAC__int32 signal[], unsigned samples);
+
+/* verify-related routines: */
+static void append_to_verify_fifo_(
+	verify_input_fifo *fifo,
+	const FLAC__int32 * const input[],
+	unsigned input_offset,
+	unsigned channels,
+	unsigned wide_samples
+);
+
+static void append_to_verify_fifo_interleaved_(
+	verify_input_fifo *fifo,
+	const FLAC__int32 input[],
+	unsigned input_offset,
+	unsigned channels,
+	unsigned wide_samples
+);
+
+static FLAC__StreamDecoderReadStatus verify_read_callback_(
+	const FLAC__StreamDecoder *decoder,
+	FLAC__byte buffer[],
+	unsigned *bytes,
+	void *client_data
+);
+
+static FLAC__StreamDecoderWriteStatus verify_write_callback_(
+	const FLAC__StreamDecoder *decoder,
+	const FLAC__Frame *frame,
+	const FLAC__int32 * const buffer[],
+	void *client_data
+);
+
+static void verify_metadata_callback_(
+	const FLAC__StreamDecoder *decoder,
+	const FLAC__StreamMetadata *metadata,
+	void *client_data
+);
+
+static void verify_error_callback_(
+	const FLAC__StreamDecoder *decoder,
+	FLAC__StreamDecoderErrorStatus status,
+	void *client_data
+);
+
+
+/***********************************************************************
+ *
+ * Private class data
+ *
+ ***********************************************************************/
+
+typedef struct FLAC__StreamEncoderPrivate {
+	unsigned input_capacity;                          /* current size (in samples) of the signal and residual buffers */
+	FLAC__int32 *integer_signal[FLAC__MAX_CHANNELS];  /* the integer version of the input signal */
+	FLAC__int32 *integer_signal_mid_side[2];          /* the integer version of the mid-side input signal (stereo only) */
+	FLAC__real *real_signal[FLAC__MAX_CHANNELS];      /* the floating-point version of the input signal */
+	FLAC__real *real_signal_mid_side[2];              /* the floating-point version of the mid-side input signal (stereo only) */
+	unsigned subframe_bps[FLAC__MAX_CHANNELS];        /* the effective bits per sample of the input signal (stream bps - wasted bits) */
+	unsigned subframe_bps_mid_side[2];                /* the effective bits per sample of the mid-side input signal (stream bps - wasted bits + 0/1) */
+	FLAC__int32 *residual_workspace[FLAC__MAX_CHANNELS][2]; /* each channel has a candidate and best workspace where the subframe residual signals will be stored */
+	FLAC__int32 *residual_workspace_mid_side[2][2];
+	FLAC__Subframe subframe_workspace[FLAC__MAX_CHANNELS][2];
+	FLAC__Subframe subframe_workspace_mid_side[2][2];
+	FLAC__Subframe *subframe_workspace_ptr[FLAC__MAX_CHANNELS][2];
+	FLAC__Subframe *subframe_workspace_ptr_mid_side[2][2];
+	FLAC__EntropyCodingMethod_PartitionedRiceContents partitioned_rice_contents_workspace[FLAC__MAX_CHANNELS][2];
+	FLAC__EntropyCodingMethod_PartitionedRiceContents partitioned_rice_contents_workspace_mid_side[FLAC__MAX_CHANNELS][2];
+	FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents_workspace_ptr[FLAC__MAX_CHANNELS][2];
+	FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents_workspace_ptr_mid_side[FLAC__MAX_CHANNELS][2];
+	unsigned best_subframe[FLAC__MAX_CHANNELS];       /* index into the above workspaces */
+	unsigned best_subframe_mid_side[2];
+	unsigned best_subframe_bits[FLAC__MAX_CHANNELS];  /* size in bits of the best subframe for each channel */
+	unsigned best_subframe_bits_mid_side[2];
+	FLAC__uint32 *abs_residual;                       /* workspace where abs(candidate residual) is stored */
+	FLAC__uint64 *abs_residual_partition_sums;        /* workspace where the sum of abs(candidate residual) for each partition is stored */
+	unsigned *raw_bits_per_partition;                 /* workspace where the sum of silog2(candidate residual) for each partition is stored */
+	FLAC__BitBuffer *frame;                           /* the current frame being worked on */
+	double loose_mid_side_stereo_frames_exact;        /* exact number of frames the encoder will use before trying both independent and mid/side frames again */
+	unsigned loose_mid_side_stereo_frames;            /* rounded number of frames the encoder will use before trying both independent and mid/side frames again */
+	unsigned loose_mid_side_stereo_frame_count;       /* number of frames using the current channel assignment */
+	FLAC__ChannelAssignment last_channel_assignment;
+	FLAC__StreamMetadata metadata;
+	unsigned current_sample_number;
+	unsigned current_frame_number;
+	struct FLAC__MD5Context md5context;
+	FLAC__CPUInfo cpuinfo;
+	unsigned (*local_fixed_compute_best_predictor)(const FLAC__int32 data[], unsigned data_len, FLAC__real residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+	void (*local_lpc_compute_autocorrelation)(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]);
+	void (*local_lpc_compute_residual_from_qlp_coefficients)(const FLAC__int32 data[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]);
+	void (*local_lpc_compute_residual_from_qlp_coefficients_64bit)(const FLAC__int32 data[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]);
+	void (*local_lpc_compute_residual_from_qlp_coefficients_16bit)(const FLAC__int32 data[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]);
+	FLAC__bool use_wide_by_block;          /* use slow 64-bit versions of some functions because of the block size */
+	FLAC__bool use_wide_by_partition;      /* use slow 64-bit versions of some functions because of the min partition order and blocksize */
+	FLAC__bool use_wide_by_order;          /* use slow 64-bit versions of some functions because of the lpc order */
+	FLAC__bool precompute_partition_sums;  /* our initial guess as to whether precomputing the partitions sums will be a speed improvement */
+	FLAC__bool disable_constant_subframes;
+	FLAC__bool disable_fixed_subframes;
+	FLAC__bool disable_verbatim_subframes;
+	FLAC__StreamEncoderWriteCallback write_callback;
+	FLAC__StreamEncoderMetadataCallback metadata_callback;
+	void *client_data;
+	/* unaligned (original) pointers to allocated data */
+	FLAC__int32 *integer_signal_unaligned[FLAC__MAX_CHANNELS];
+	FLAC__int32 *integer_signal_mid_side_unaligned[2];
+	FLAC__real *real_signal_unaligned[FLAC__MAX_CHANNELS];
+	FLAC__real *real_signal_mid_side_unaligned[2];
+	FLAC__int32 *residual_workspace_unaligned[FLAC__MAX_CHANNELS][2];
+	FLAC__int32 *residual_workspace_mid_side_unaligned[2][2];
+	FLAC__uint32 *abs_residual_unaligned;
+	FLAC__uint64 *abs_residual_partition_sums_unaligned;
+	unsigned *raw_bits_per_partition_unaligned;
+	/*
+	 * These fields have been moved here from private function local
+	 * declarations merely to save stack space during encoding.
+	 */
+	FLAC__real lp_coeff[FLAC__MAX_LPC_ORDER][FLAC__MAX_LPC_ORDER]; /* from process_subframe_() */
+	FLAC__EntropyCodingMethod_PartitionedRiceContents partitioned_rice_contents_extra[2]; /* from find_best_partition_order_() */
+	/*
+	 * The data for the verify section
+	 */
+	struct {
+		FLAC__StreamDecoder *decoder;
+		EncoderStateHint state_hint;
+		FLAC__bool needs_magic_hack;
+		verify_input_fifo input_fifo;
+		verify_output output;
+		struct {
+			FLAC__uint64 absolute_sample;
+			unsigned frame_number;
+			unsigned channel;
+			unsigned sample;
+			FLAC__int32 expected;
+			FLAC__int32 got;
+		} error_stats;
+	} verify;
+	FLAC__bool is_being_deleted; /* if true, call to ..._finish() from ..._delete() will not call the callbacks */
+} FLAC__StreamEncoderPrivate;
+
+/***********************************************************************
+ *
+ * Public static class data
+ *
+ ***********************************************************************/
+
+FLAC_API const char * const FLAC__StreamEncoderStateString[] = {
+	"FLAC__STREAM_ENCODER_OK",
+	"FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR",
+	"FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA",
+	"FLAC__STREAM_ENCODER_INVALID_CALLBACK",
+	"FLAC__STREAM_ENCODER_INVALID_NUMBER_OF_CHANNELS",
+	"FLAC__STREAM_ENCODER_INVALID_BITS_PER_SAMPLE",
+	"FLAC__STREAM_ENCODER_INVALID_SAMPLE_RATE",
+	"FLAC__STREAM_ENCODER_INVALID_BLOCK_SIZE",
+	"FLAC__STREAM_ENCODER_INVALID_MAX_LPC_ORDER",
+	"FLAC__STREAM_ENCODER_INVALID_QLP_COEFF_PRECISION",
+	"FLAC__STREAM_ENCODER_MID_SIDE_CHANNELS_MISMATCH",
+	"FLAC__STREAM_ENCODER_MID_SIDE_SAMPLE_SIZE_MISMATCH",
+	"FLAC__STREAM_ENCODER_ILLEGAL_MID_SIDE_FORCE",
+	"FLAC__STREAM_ENCODER_BLOCK_SIZE_TOO_SMALL_FOR_LPC_ORDER",
+	"FLAC__STREAM_ENCODER_NOT_STREAMABLE",
+	"FLAC__STREAM_ENCODER_FRAMING_ERROR",
+	"FLAC__STREAM_ENCODER_INVALID_METADATA",
+	"FLAC__STREAM_ENCODER_FATAL_ERROR_WHILE_ENCODING",
+	"FLAC__STREAM_ENCODER_FATAL_ERROR_WHILE_WRITING",
+	"FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR",
+	"FLAC__STREAM_ENCODER_ALREADY_INITIALIZED",
+	"FLAC__STREAM_ENCODER_UNINITIALIZED"
+};
+
+FLAC_API const char * const FLAC__StreamEncoderWriteStatusString[] = {
+	"FLAC__STREAM_ENCODER_WRITE_STATUS_OK",
+	"FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR"
+};
+
+/***********************************************************************
+ *
+ * Class constructor/destructor
+ *
+ */
+FLAC_API FLAC__StreamEncoder *FLAC__stream_encoder_new()
+{
+	FLAC__StreamEncoder *encoder;
+	unsigned i;
+
+	FLAC__ASSERT(sizeof(int) >= 4); /* we want to die right away if this is not true */
+
+	encoder = (FLAC__StreamEncoder*)calloc(1, sizeof(FLAC__StreamEncoder));
+	if(encoder == 0) {
+		return 0;
+	}
+
+	encoder->protected_ = (FLAC__StreamEncoderProtected*)calloc(1, sizeof(FLAC__StreamEncoderProtected));
+	if(encoder->protected_ == 0) {
+		free(encoder);
+		return 0;
+	}
+
+	encoder->private_ = (FLAC__StreamEncoderPrivate*)calloc(1, sizeof(FLAC__StreamEncoderPrivate));
+	if(encoder->private_ == 0) {
+		free(encoder->protected_);
+		free(encoder);
+		return 0;
+	}
+
+	encoder->private_->frame = FLAC__bitbuffer_new();
+	if(encoder->private_->frame == 0) {
+		free(encoder->private_);
+		free(encoder->protected_);
+		free(encoder);
+		return 0;
+	}
+
+	set_defaults_(encoder);
+
+	encoder->private_->is_being_deleted = false;
+
+	for(i = 0; i < FLAC__MAX_CHANNELS; i++) {
+		encoder->private_->subframe_workspace_ptr[i][0] = &encoder->private_->subframe_workspace[i][0];
+		encoder->private_->subframe_workspace_ptr[i][1] = &encoder->private_->subframe_workspace[i][1];
+	}
+	for(i = 0; i < 2; i++) {
+		encoder->private_->subframe_workspace_ptr_mid_side[i][0] = &encoder->private_->subframe_workspace_mid_side[i][0];
+		encoder->private_->subframe_workspace_ptr_mid_side[i][1] = &encoder->private_->subframe_workspace_mid_side[i][1];
+	}
+	for(i = 0; i < FLAC__MAX_CHANNELS; i++) {
+		encoder->private_->partitioned_rice_contents_workspace_ptr[i][0] = &encoder->private_->partitioned_rice_contents_workspace[i][0];
+		encoder->private_->partitioned_rice_contents_workspace_ptr[i][1] = &encoder->private_->partitioned_rice_contents_workspace[i][1];
+	}
+	for(i = 0; i < 2; i++) {
+		encoder->private_->partitioned_rice_contents_workspace_ptr_mid_side[i][0] = &encoder->private_->partitioned_rice_contents_workspace_mid_side[i][0];
+		encoder->private_->partitioned_rice_contents_workspace_ptr_mid_side[i][1] = &encoder->private_->partitioned_rice_contents_workspace_mid_side[i][1];
+	}
+
+	for(i = 0; i < FLAC__MAX_CHANNELS; i++) {
+		FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&encoder->private_->partitioned_rice_contents_workspace[i][0]);
+		FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&encoder->private_->partitioned_rice_contents_workspace[i][1]);
+	}
+	for(i = 0; i < 2; i++) {
+		FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&encoder->private_->partitioned_rice_contents_workspace_mid_side[i][0]);
+		FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&encoder->private_->partitioned_rice_contents_workspace_mid_side[i][1]);
+	}
+	for(i = 0; i < 2; i++)
+		FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&encoder->private_->partitioned_rice_contents_extra[i]);
+
+	encoder->protected_->state = FLAC__STREAM_ENCODER_UNINITIALIZED;
+
+	return encoder;
+}
+
+FLAC_API void FLAC__stream_encoder_delete(FLAC__StreamEncoder *encoder)
+{
+	unsigned i;
+
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->protected_);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->private_->frame);
+
+	encoder->private_->is_being_deleted = true;
+
+	FLAC__stream_encoder_finish(encoder);
+
+	if(0 != encoder->private_->verify.decoder)
+		FLAC__stream_decoder_delete(encoder->private_->verify.decoder);
+
+	for(i = 0; i < FLAC__MAX_CHANNELS; i++) {
+		FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&encoder->private_->partitioned_rice_contents_workspace[i][0]);
+		FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&encoder->private_->partitioned_rice_contents_workspace[i][1]);
+	}
+	for(i = 0; i < 2; i++) {
+		FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&encoder->private_->partitioned_rice_contents_workspace_mid_side[i][0]);
+		FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&encoder->private_->partitioned_rice_contents_workspace_mid_side[i][1]);
+	}
+	for(i = 0; i < 2; i++)
+		FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&encoder->private_->partitioned_rice_contents_extra[i]);
+
+	FLAC__bitbuffer_delete(encoder->private_->frame);
+	free(encoder->private_);
+	free(encoder->protected_);
+	free(encoder);
+}
+
+/***********************************************************************
+ *
+ * Public class methods
+ *
+ ***********************************************************************/
+
+FLAC_API FLAC__StreamEncoderState FLAC__stream_encoder_init(FLAC__StreamEncoder *encoder)
+{
+	unsigned i;
+	FLAC__bool metadata_has_seektable, metadata_has_vorbis_comment;
+
+	FLAC__ASSERT(0 != encoder);
+
+	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+		return encoder->protected_->state = FLAC__STREAM_ENCODER_ALREADY_INITIALIZED;
+
+	encoder->protected_->state = FLAC__STREAM_ENCODER_OK;
+
+	if(0 == encoder->private_->write_callback || 0 == encoder->private_->metadata_callback)
+		return encoder->protected_->state = FLAC__STREAM_ENCODER_INVALID_CALLBACK;
+
+	if(encoder->protected_->channels == 0 || encoder->protected_->channels > FLAC__MAX_CHANNELS)
+		return encoder->protected_->state = FLAC__STREAM_ENCODER_INVALID_NUMBER_OF_CHANNELS;
+
+	if(encoder->protected_->do_mid_side_stereo && encoder->protected_->channels != 2)
+		return encoder->protected_->state = FLAC__STREAM_ENCODER_MID_SIDE_CHANNELS_MISMATCH;
+
+	if(encoder->protected_->loose_mid_side_stereo && !encoder->protected_->do_mid_side_stereo)
+		return encoder->protected_->state = FLAC__STREAM_ENCODER_ILLEGAL_MID_SIDE_FORCE;
+
+	if(encoder->protected_->bits_per_sample >= 32)
+		encoder->protected_->do_mid_side_stereo = false; /* since we do 32-bit math, the side channel would have 33 bps and overflow */
+
+	if(encoder->protected_->bits_per_sample < FLAC__MIN_BITS_PER_SAMPLE || encoder->protected_->bits_per_sample > FLAC__REFERENCE_CODEC_MAX_BITS_PER_SAMPLE)
+		return encoder->protected_->state = FLAC__STREAM_ENCODER_INVALID_BITS_PER_SAMPLE;
+
+	if(!FLAC__format_sample_rate_is_valid(encoder->protected_->sample_rate))
+		return encoder->protected_->state = FLAC__STREAM_ENCODER_INVALID_SAMPLE_RATE;
+
+	if(encoder->protected_->blocksize < FLAC__MIN_BLOCK_SIZE || encoder->protected_->blocksize > FLAC__MAX_BLOCK_SIZE)
+		return encoder->protected_->state = FLAC__STREAM_ENCODER_INVALID_BLOCK_SIZE;
+
+	if(encoder->protected_->max_lpc_order > FLAC__MAX_LPC_ORDER)
+		return encoder->protected_->state = FLAC__STREAM_ENCODER_INVALID_MAX_LPC_ORDER;
+
+	if(encoder->protected_->blocksize < encoder->protected_->max_lpc_order)
+		return encoder->protected_->state = FLAC__STREAM_ENCODER_BLOCK_SIZE_TOO_SMALL_FOR_LPC_ORDER;
+
+	if(encoder->protected_->qlp_coeff_precision == 0) {
+		if(encoder->protected_->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->protected_->qlp_coeff_precision = max(FLAC__MIN_QLP_COEFF_PRECISION, 2 + encoder->protected_->bits_per_sample / 2);
+		}
+		else if(encoder->protected_->bits_per_sample == 16) {
+			if(encoder->protected_->blocksize <= 192)
+				encoder->protected_->qlp_coeff_precision = 7;
+			else if(encoder->protected_->blocksize <= 384)
+				encoder->protected_->qlp_coeff_precision = 8;
+			else if(encoder->protected_->blocksize <= 576)
+				encoder->protected_->qlp_coeff_precision = 9;
+			else if(encoder->protected_->blocksize <= 1152)
+				encoder->protected_->qlp_coeff_precision = 10;
+			else if(encoder->protected_->blocksize <= 2304)
+				encoder->protected_->qlp_coeff_precision = 11;
+			else if(encoder->protected_->blocksize <= 4608)
+				encoder->protected_->qlp_coeff_precision = 12;
+			else
+				encoder->protected_->qlp_coeff_precision = 13;
+		}
+		else {
+			if(encoder->protected_->blocksize <= 384)
+				encoder->protected_->qlp_coeff_precision = FLAC__MAX_QLP_COEFF_PRECISION-2;
+			else if(encoder->protected_->blocksize <= 1152)
+				encoder->protected_->qlp_coeff_precision = FLAC__MAX_QLP_COEFF_PRECISION-1;
+			else
+				encoder->protected_->qlp_coeff_precision = FLAC__MAX_QLP_COEFF_PRECISION;
+		}
+		FLAC__ASSERT(encoder->protected_->qlp_coeff_precision <= FLAC__MAX_QLP_COEFF_PRECISION);
+	}
+	else if(encoder->protected_->qlp_coeff_precision < FLAC__MIN_QLP_COEFF_PRECISION || encoder->protected_->qlp_coeff_precision > FLAC__MAX_QLP_COEFF_PRECISION)
+		return encoder->protected_->state = FLAC__STREAM_ENCODER_INVALID_QLP_COEFF_PRECISION;
+
+	if(encoder->protected_->streamable_subset) {
+		if(
+			encoder->protected_->blocksize != 192 &&
+			encoder->protected_->blocksize != 576 &&
+			encoder->protected_->blocksize != 1152 &&
+			encoder->protected_->blocksize != 2304 &&
+			encoder->protected_->blocksize != 4608 &&
+			encoder->protected_->blocksize != 256 &&
+			encoder->protected_->blocksize != 512 &&
+			encoder->protected_->blocksize != 1024 &&
+			encoder->protected_->blocksize != 2048 &&
+			encoder->protected_->blocksize != 4096 &&
+			encoder->protected_->blocksize != 8192 &&
+			encoder->protected_->blocksize != 16384
+		)
+			return encoder->protected_->state = FLAC__STREAM_ENCODER_NOT_STREAMABLE;
+		if(
+			encoder->protected_->sample_rate != 8000 &&
+			encoder->protected_->sample_rate != 16000 &&
+			encoder->protected_->sample_rate != 22050 &&
+			encoder->protected_->sample_rate != 24000 &&
+			encoder->protected_->sample_rate != 32000 &&
+			encoder->protected_->sample_rate != 44100 &&
+			encoder->protected_->sample_rate != 48000 &&
+			encoder->protected_->sample_rate != 96000
+		)
+			return encoder->protected_->state = FLAC__STREAM_ENCODER_NOT_STREAMABLE;
+		if(
+			encoder->protected_->bits_per_sample != 8 &&
+			encoder->protected_->bits_per_sample != 12 &&
+			encoder->protected_->bits_per_sample != 16 &&
+			encoder->protected_->bits_per_sample != 20 &&
+			encoder->protected_->bits_per_sample != 24
+		)
+			return encoder->protected_->state = FLAC__STREAM_ENCODER_NOT_STREAMABLE;
+		if(encoder->protected_->max_residual_partition_order > FLAC__SUBSET_MAX_RICE_PARTITION_ORDER)
+			return encoder->protected_->state = FLAC__STREAM_ENCODER_NOT_STREAMABLE;
+	}
+
+	if(encoder->protected_->max_residual_partition_order >= (1u << FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN))
+		encoder->protected_->max_residual_partition_order = (1u << FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN) - 1;
+	if(encoder->protected_->min_residual_partition_order >= encoder->protected_->max_residual_partition_order)
+		encoder->protected_->min_residual_partition_order = encoder->protected_->max_residual_partition_order;
+
+	/* validate metadata */
+	if(0 == encoder->protected_->metadata && encoder->protected_->num_metadata_blocks > 0)
+		return encoder->protected_->state = FLAC__STREAM_ENCODER_INVALID_METADATA;
+	metadata_has_seektable = false;
+	metadata_has_vorbis_comment = false;
+	for(i = 0; i < encoder->protected_->num_metadata_blocks; i++) {
+		if(encoder->protected_->metadata[i]->type == FLAC__METADATA_TYPE_STREAMINFO)
+			return encoder->protected_->state = FLAC__STREAM_ENCODER_INVALID_METADATA;
+		else if(encoder->protected_->metadata[i]->type == FLAC__METADATA_TYPE_SEEKTABLE) {
+			if(metadata_has_seektable) /* only one is allowed */
+				return encoder->protected_->state = FLAC__STREAM_ENCODER_INVALID_METADATA;
+			metadata_has_seektable = true;
+			if(!FLAC__format_seektable_is_legal(&encoder->protected_->metadata[i]->data.seek_table))
+				return encoder->protected_->state = FLAC__STREAM_ENCODER_INVALID_METADATA;
+		}
+		else if(encoder->protected_->metadata[i]->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
+			if(metadata_has_vorbis_comment) /* only one is allowed */
+				return encoder->protected_->state = FLAC__STREAM_ENCODER_INVALID_METADATA;
+			metadata_has_vorbis_comment = true;
+		}
+		else if(encoder->protected_->metadata[i]->type == FLAC__METADATA_TYPE_CUESHEET) {
+			if(!FLAC__format_cuesheet_is_legal(&encoder->protected_->metadata[i]->data.cue_sheet, encoder->protected_->metadata[i]->data.cue_sheet.is_cd, /*violation=*/0))
+				return encoder->protected_->state = FLAC__STREAM_ENCODER_INVALID_METADATA;
+		}
+	}
+
+	encoder->private_->input_capacity = 0;
+	for(i = 0; i < encoder->protected_->channels; i++) {
+		encoder->private_->integer_signal_unaligned[i] = encoder->private_->integer_signal[i] = 0;
+		encoder->private_->real_signal_unaligned[i] = encoder->private_->real_signal[i] = 0;
+	}
+	for(i = 0; i < 2; i++) {
+		encoder->private_->integer_signal_mid_side_unaligned[i] = encoder->private_->integer_signal_mid_side[i] = 0;
+		encoder->private_->real_signal_mid_side_unaligned[i] = encoder->private_->real_signal_mid_side[i] = 0;
+	}
+	for(i = 0; i < encoder->protected_->channels; i++) {
+		encoder->private_->residual_workspace_unaligned[i][0] = encoder->private_->residual_workspace[i][0] = 0;
+		encoder->private_->residual_workspace_unaligned[i][1] = encoder->private_->residual_workspace[i][1] = 0;
+		encoder->private_->best_subframe[i] = 0;
+	}
+	for(i = 0; i < 2; i++) {
+		encoder->private_->residual_workspace_mid_side_unaligned[i][0] = encoder->private_->residual_workspace_mid_side[i][0] = 0;
+		encoder->private_->residual_workspace_mid_side_unaligned[i][1] = encoder->private_->residual_workspace_mid_side[i][1] = 0;
+		encoder->private_->best_subframe_mid_side[i] = 0;
+	}
+	encoder->private_->abs_residual_unaligned = encoder->private_->abs_residual = 0;
+	encoder->private_->abs_residual_partition_sums_unaligned = encoder->private_->abs_residual_partition_sums = 0;
+	encoder->private_->raw_bits_per_partition_unaligned = encoder->private_->raw_bits_per_partition = 0;
+	encoder->private_->loose_mid_side_stereo_frames_exact = (double)encoder->protected_->sample_rate * 0.4 / (double)encoder->protected_->blocksize;
+	encoder->private_->loose_mid_side_stereo_frames = (unsigned)(encoder->private_->loose_mid_side_stereo_frames_exact + 0.5);
+	if(encoder->private_->loose_mid_side_stereo_frames == 0)
+		encoder->private_->loose_mid_side_stereo_frames = 1;
+	encoder->private_->loose_mid_side_stereo_frame_count = 0;
+	encoder->private_->current_sample_number = 0;
+	encoder->private_->current_frame_number = 0;
+
+	encoder->private_->use_wide_by_block = (encoder->protected_->bits_per_sample + FLAC__bitmath_ilog2(encoder->protected_->blocksize)+1 > 30);
+	encoder->private_->use_wide_by_order = (encoder->protected_->bits_per_sample + FLAC__bitmath_ilog2(max(encoder->protected_->max_lpc_order, FLAC__MAX_FIXED_ORDER))+1 > 30); /*@@@ need to use this? */
+	encoder->private_->use_wide_by_partition = (false); /*@@@ need to set this */
+
+	/*
+	 * get the CPU info and set the function pointers
+	 */
+	FLAC__cpu_info(&encoder->private_->cpuinfo);
+	/* first default to the non-asm routines */
+	encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation;
+	encoder->private_->local_fixed_compute_best_predictor = FLAC__fixed_compute_best_predictor;
+	encoder->private_->local_lpc_compute_residual_from_qlp_coefficients = FLAC__lpc_compute_residual_from_qlp_coefficients;
+	encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_64bit = FLAC__lpc_compute_residual_from_qlp_coefficients_wide;
+	encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit = FLAC__lpc_compute_residual_from_qlp_coefficients;
+	/* now override with asm where appropriate */
+#ifndef FLAC__NO_ASM
+	if(encoder->private_->cpuinfo.use_asm) {
+#ifdef FLAC__CPU_IA32
+		FLAC__ASSERT(encoder->private_->cpuinfo.type == FLAC__CPUINFO_TYPE_IA32);
+#ifdef FLAC__HAS_NASM
+#ifdef FLAC__SSE_OS
+		if(encoder->private_->cpuinfo.data.ia32.sse) {
+			if(encoder->protected_->max_lpc_order < 4)
+				encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_4;
+			else if(encoder->protected_->max_lpc_order < 8)
+				encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_8;
+			else if(encoder->protected_->max_lpc_order < 12)
+				encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_12;
+			else
+				encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32;
+		}
+		else
+#endif
+		if(encoder->private_->cpuinfo.data.ia32._3dnow)
+			encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32_3dnow;
+		else
+			encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32;
+		if(encoder->private_->cpuinfo.data.ia32.mmx && encoder->private_->cpuinfo.data.ia32.cmov)
+			encoder->private_->local_fixed_compute_best_predictor = FLAC__fixed_compute_best_predictor_asm_ia32_mmx_cmov;
+		if(encoder->private_->cpuinfo.data.ia32.mmx) {
+			encoder->private_->local_lpc_compute_residual_from_qlp_coefficients = FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32;
+			encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit = FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32_mmx;
+		}
+		else {
+			encoder->private_->local_lpc_compute_residual_from_qlp_coefficients = FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32;
+			encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit = FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32;
+		}
+#endif
+#endif
+	}
+#endif
+	/* finally override based on wide-ness if necessary */
+	if(encoder->private_->use_wide_by_block) {
+		encoder->private_->local_fixed_compute_best_predictor = FLAC__fixed_compute_best_predictor_wide;
+	}
+
+	/* we require precompute_partition_sums if do_escape_coding because of their intertwined nature */
+	encoder->private_->precompute_partition_sums = (encoder->protected_->max_residual_partition_order > encoder->protected_->min_residual_partition_order) || encoder->protected_->do_escape_coding;
+
+	if(!resize_buffers_(encoder, encoder->protected_->blocksize)) {
+		/* the above function sets the state for us in case of an error */
+		return encoder->protected_->state;
+	}
+
+	if(!FLAC__bitbuffer_init(encoder->private_->frame))
+		return encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR;
+
+	/*
+	 * Set up the verify stuff if necessary
+	 */
+	if(encoder->protected_->verify) {
+		/*
+		 * First, set up the fifo which will hold the
+		 * original signal to compare against
+		 */
+		encoder->private_->verify.input_fifo.size = encoder->protected_->blocksize;
+		for(i = 0; i < encoder->protected_->channels; i++) {
+			if(0 == (encoder->private_->verify.input_fifo.data[i] = (FLAC__int32*)malloc(sizeof(FLAC__int32) * encoder->private_->verify.input_fifo.size)))
+				return encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR;
+		}
+		encoder->private_->verify.input_fifo.tail = 0;
+
+		/*
+		 * Now set up a stream decoder for verification
+		 */
+		encoder->private_->verify.decoder = FLAC__stream_decoder_new();
+		if(0 == encoder->private_->verify.decoder)
+			return encoder->protected_->state = FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR;
+
+		FLAC__stream_decoder_set_read_callback(encoder->private_->verify.decoder, verify_read_callback_);
+		FLAC__stream_decoder_set_write_callback(encoder->private_->verify.decoder, verify_write_callback_);
+		FLAC__stream_decoder_set_metadata_callback(encoder->private_->verify.decoder, verify_metadata_callback_);
+		FLAC__stream_decoder_set_error_callback(encoder->private_->verify.decoder, verify_error_callback_);
+		FLAC__stream_decoder_set_client_data(encoder->private_->verify.decoder, encoder);
+		if(FLAC__stream_decoder_init(encoder->private_->verify.decoder) != FLAC__STREAM_DECODER_SEARCH_FOR_METADATA)
+			return encoder->protected_->state = FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR;
+	}
+	encoder->private_->verify.error_stats.absolute_sample = 0;
+	encoder->private_->verify.error_stats.frame_number = 0;
+	encoder->private_->verify.error_stats.channel = 0;
+	encoder->private_->verify.error_stats.sample = 0;
+	encoder->private_->verify.error_stats.expected = 0;
+	encoder->private_->verify.error_stats.got = 0;
+
+	/*
+	 * write the stream header
+	 */
+	if(encoder->protected_->verify)
+		encoder->private_->verify.state_hint = ENCODER_IN_MAGIC;
+	if(!FLAC__bitbuffer_write_raw_uint32(encoder->private_->frame, FLAC__STREAM_SYNC, FLAC__STREAM_SYNC_LEN))
+		return encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR;
+	if(!write_bitbuffer_(encoder, 0)) {
+		/* the above function sets the state for us in case of an error */
+		return encoder->protected_->state;
+	}
+
+	/*
+	 * write the STREAMINFO metadata block
+	 */
+	if(encoder->protected_->verify)
+		encoder->private_->verify.state_hint = ENCODER_IN_METADATA;
+	encoder->private_->metadata.type = FLAC__METADATA_TYPE_STREAMINFO;
+	encoder->private_->metadata.is_last = false; /* we will have at a minimum a VORBIS_COMMENT afterwards */
+	encoder->private_->metadata.length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH;
+	encoder->private_->metadata.data.stream_info.min_blocksize = encoder->protected_->blocksize; /* this encoder uses the same blocksize for the whole stream */
+	encoder->private_->metadata.data.stream_info.max_blocksize = encoder->protected_->blocksize;
+	encoder->private_->metadata.data.stream_info.min_framesize = 0; /* we don't know this yet; have to fill it in later */
+	encoder->private_->metadata.data.stream_info.max_framesize = 0; /* we don't know this yet; have to fill it in later */
+	encoder->private_->metadata.data.stream_info.sample_rate = encoder->protected_->sample_rate;
+	encoder->private_->metadata.data.stream_info.channels = encoder->protected_->channels;
+	encoder->private_->metadata.data.stream_info.bits_per_sample = encoder->protected_->bits_per_sample;
+	encoder->private_->metadata.data.stream_info.total_samples = encoder->protected_->total_samples_estimate; /* we will replace this later with the real total */
+	memset(encoder->private_->metadata.data.stream_info.md5sum, 0, 16); /* we don't know this yet; have to fill it in later */
+	FLAC__MD5Init(&encoder->private_->md5context);
+	if(!FLAC__bitbuffer_clear(encoder->private_->frame))
+		return encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR;
+	if(!FLAC__add_metadata_block(&encoder->private_->metadata, encoder->private_->frame))
+		return encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR;
+	if(!write_bitbuffer_(encoder, 0)) {
+		/* the above function sets the state for us in case of an error */
+		return encoder->protected_->state;
+	}
+
+	/*
+	 * Now that the STREAMINFO block is written, we can init this to an
+	 * absurdly-high value...
+	 */
+	encoder->private_->metadata.data.stream_info.min_framesize = (1u << FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN) - 1;
+	/* ... and clear this to 0 */
+	encoder->private_->metadata.data.stream_info.total_samples = 0;
+
+	/*
+	 * Check to see if the supplied metadata contains a VORBIS_COMMENT;
+	 * if not, we will write an empty one (FLAC__add_metadata_block()
+	 * automatically supplies the vendor string).
+	 *
+	 * WATCHOUT: libOggFLAC depends on us to write this block after the
+	 * STREAMINFO since that's what the mapping requires.  (In the case
+	 * that metadata_has_vorbis_comment it true it will have already
+	 * insured that the metadata list is properly ordered.)
+	 */
+	if(!metadata_has_vorbis_comment) {
+		FLAC__StreamMetadata vorbis_comment;
+		vorbis_comment.type = FLAC__METADATA_TYPE_VORBIS_COMMENT;
+		vorbis_comment.is_last = (encoder->protected_->num_metadata_blocks == 0);
+		vorbis_comment.length = 4 + 4; /* MAGIC NUMBER */
+		vorbis_comment.data.vorbis_comment.vendor_string.length = 0;
+		vorbis_comment.data.vorbis_comment.vendor_string.entry = 0;
+		vorbis_comment.data.vorbis_comment.num_comments = 0;
+		vorbis_comment.data.vorbis_comment.comments = 0;
+		if(!FLAC__bitbuffer_clear(encoder->private_->frame))
+			return encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR;
+		if(!FLAC__add_metadata_block(&vorbis_comment, encoder->private_->frame))
+			return encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR;
+		if(!write_bitbuffer_(encoder, 0)) {
+			/* the above function sets the state for us in case of an error */
+			return encoder->protected_->state;
+		}
+	}
+
+	/*
+	 * write the user's metadata blocks
+	 */
+	for(i = 0; i < encoder->protected_->num_metadata_blocks; i++) {
+		encoder->protected_->metadata[i]->is_last = (i == encoder->protected_->num_metadata_blocks - 1);
+		if(!FLAC__bitbuffer_clear(encoder->private_->frame))
+			return encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR;
+		if(!FLAC__add_metadata_block(encoder->protected_->metadata[i], encoder->private_->frame))
+			return encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR;
+		if(!write_bitbuffer_(encoder, 0)) {
+			/* the above function sets the state for us in case of an error */
+			return encoder->protected_->state;
+		}
+	}
+
+	if(encoder->protected_->verify)
+		encoder->private_->verify.state_hint = ENCODER_IN_AUDIO;
+
+	return encoder->protected_->state;
+}
+
+FLAC_API void FLAC__stream_encoder_finish(FLAC__StreamEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+
+	if(encoder->protected_->state == FLAC__STREAM_ENCODER_UNINITIALIZED)
+		return;
+
+	if(encoder->protected_->state == FLAC__STREAM_ENCODER_OK && !encoder->private_->is_being_deleted) {
+		if(encoder->private_->current_sample_number != 0) {
+			encoder->protected_->blocksize = encoder->private_->current_sample_number;
+			process_frame_(encoder, true); /* true => is last frame */
+		}
+	}
+
+	FLAC__MD5Final(encoder->private_->metadata.data.stream_info.md5sum, &encoder->private_->md5context);
+
+	if(encoder->protected_->state == FLAC__STREAM_ENCODER_OK && !encoder->private_->is_being_deleted) {
+		encoder->private_->metadata_callback(encoder, &encoder->private_->metadata, encoder->private_->client_data);
+	}
+
+	if(encoder->protected_->verify && 0 != encoder->private_->verify.decoder)
+		FLAC__stream_decoder_finish(encoder->private_->verify.decoder);
+
+	free_(encoder);
+	set_defaults_(encoder);
+
+	encoder->protected_->state = FLAC__STREAM_ENCODER_UNINITIALIZED;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_verify(FLAC__StreamEncoder *encoder, FLAC__bool value)
+{
+	FLAC__ASSERT(0 != encoder);
+	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+		return false;
+	encoder->protected_->verify = value;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_streamable_subset(FLAC__StreamEncoder *encoder, FLAC__bool value)
+{
+	FLAC__ASSERT(0 != encoder);
+	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+		return false;
+	encoder->protected_->streamable_subset = value;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_do_mid_side_stereo(FLAC__StreamEncoder *encoder, FLAC__bool value)
+{
+	FLAC__ASSERT(0 != encoder);
+	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+		return false;
+	encoder->protected_->do_mid_side_stereo = value;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_loose_mid_side_stereo(FLAC__StreamEncoder *encoder, FLAC__bool value)
+{
+	FLAC__ASSERT(0 != encoder);
+	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+		return false;
+	encoder->protected_->loose_mid_side_stereo = value;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_channels(FLAC__StreamEncoder *encoder, unsigned value)
+{
+	FLAC__ASSERT(0 != encoder);
+	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+		return false;
+	encoder->protected_->channels = value;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_bits_per_sample(FLAC__StreamEncoder *encoder, unsigned value)
+{
+	FLAC__ASSERT(0 != encoder);
+	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+		return false;
+	encoder->protected_->bits_per_sample = value;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_sample_rate(FLAC__StreamEncoder *encoder, unsigned value)
+{
+	FLAC__ASSERT(0 != encoder);
+	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+		return false;
+	encoder->protected_->sample_rate = value;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_blocksize(FLAC__StreamEncoder *encoder, unsigned value)
+{
+	FLAC__ASSERT(0 != encoder);
+	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+		return false;
+	encoder->protected_->blocksize = value;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_max_lpc_order(FLAC__StreamEncoder *encoder, unsigned value)
+{
+	FLAC__ASSERT(0 != encoder);
+	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+		return false;
+	encoder->protected_->max_lpc_order = value;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_qlp_coeff_precision(FLAC__StreamEncoder *encoder, unsigned value)
+{
+	FLAC__ASSERT(0 != encoder);
+	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+		return false;
+	encoder->protected_->qlp_coeff_precision = value;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_do_qlp_coeff_prec_search(FLAC__StreamEncoder *encoder, FLAC__bool value)
+{
+	FLAC__ASSERT(0 != encoder);
+	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+		return false;
+	encoder->protected_->do_qlp_coeff_prec_search = value;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_do_escape_coding(FLAC__StreamEncoder *encoder, FLAC__bool value)
+{
+	FLAC__ASSERT(0 != encoder);
+	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+		return false;
+#if 0
+	/*@@@ deprecated: */
+	encoder->protected_->do_escape_coding = value;
+#else
+	(void)value;
+#endif
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_do_exhaustive_model_search(FLAC__StreamEncoder *encoder, FLAC__bool value)
+{
+	FLAC__ASSERT(0 != encoder);
+	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+		return false;
+	encoder->protected_->do_exhaustive_model_search = value;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_min_residual_partition_order(FLAC__StreamEncoder *encoder, unsigned value)
+{
+	FLAC__ASSERT(0 != encoder);
+	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+		return false;
+	encoder->protected_->min_residual_partition_order = value;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_max_residual_partition_order(FLAC__StreamEncoder *encoder, unsigned value)
+{
+	FLAC__ASSERT(0 != encoder);
+	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+		return false;
+	encoder->protected_->max_residual_partition_order = value;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_rice_parameter_search_dist(FLAC__StreamEncoder *encoder, unsigned value)
+{
+	FLAC__ASSERT(0 != encoder);
+	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+		return false;
+#if 0
+	/*@@@ deprecated: */
+	encoder->protected_->rice_parameter_search_dist = value;
+#else
+	(void)value;
+#endif
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_total_samples_estimate(FLAC__StreamEncoder *encoder, FLAC__uint64 value)
+{
+	FLAC__ASSERT(0 != encoder);
+	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+		return false;
+	encoder->protected_->total_samples_estimate = value;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_metadata(FLAC__StreamEncoder *encoder, FLAC__StreamMetadata **metadata, unsigned num_blocks)
+{
+	FLAC__ASSERT(0 != encoder);
+	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+		return false;
+	encoder->protected_->metadata = metadata;
+	encoder->protected_->num_metadata_blocks = num_blocks;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_write_callback(FLAC__StreamEncoder *encoder, FLAC__StreamEncoderWriteCallback value)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != value);
+	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+		return false;
+	encoder->private_->write_callback = value;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_metadata_callback(FLAC__StreamEncoder *encoder, FLAC__StreamEncoderMetadataCallback value)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != value);
+	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+		return false;
+	encoder->private_->metadata_callback = value;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_client_data(FLAC__StreamEncoder *encoder, void *value)
+{
+	FLAC__ASSERT(0 != encoder);
+	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+		return false;
+	encoder->private_->client_data = value;
+	return true;
+}
+
+/*
+ * These three functions are not static, but not publically exposed in
+ * include/FLAC/ either.  They are used by the test suite.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_disable_constant_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value)
+{
+	FLAC__ASSERT(0 != encoder);
+	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+		return false;
+	encoder->private_->disable_constant_subframes = value;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_disable_fixed_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value)
+{
+	FLAC__ASSERT(0 != encoder);
+	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+		return false;
+	encoder->private_->disable_fixed_subframes = value;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_disable_verbatim_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value)
+{
+	FLAC__ASSERT(0 != encoder);
+	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+		return false;
+	encoder->private_->disable_verbatim_subframes = value;
+	return true;
+}
+
+FLAC_API FLAC__StreamEncoderState FLAC__stream_encoder_get_state(const FLAC__StreamEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	return encoder->protected_->state;
+}
+
+FLAC_API FLAC__StreamDecoderState FLAC__stream_encoder_get_verify_decoder_state(const FLAC__StreamEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	if(encoder->protected_->verify)
+		return FLAC__stream_decoder_get_state(encoder->private_->verify.decoder);
+	else
+		return FLAC__STREAM_DECODER_UNINITIALIZED;
+}
+
+FLAC_API const char *FLAC__stream_encoder_get_resolved_state_string(const FLAC__StreamEncoder *encoder)
+{
+	if(encoder->protected_->state != FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR)
+		return FLAC__StreamEncoderStateString[encoder->protected_->state];
+	else
+		return FLAC__stream_decoder_get_resolved_state_string(encoder->private_->verify.decoder);
+}
+
+FLAC_API void FLAC__stream_encoder_get_verify_decoder_error_stats(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_sample, unsigned *frame_number, unsigned *channel, unsigned *sample, FLAC__int32 *expected, FLAC__int32 *got)
+{
+	FLAC__ASSERT(0 != encoder);
+	if(0 != absolute_sample)
+		*absolute_sample = encoder->private_->verify.error_stats.absolute_sample;
+	if(0 != frame_number)
+		*frame_number = encoder->private_->verify.error_stats.frame_number;
+	if(0 != channel)
+		*channel = encoder->private_->verify.error_stats.channel;
+	if(0 != sample)
+		*sample = encoder->private_->verify.error_stats.sample;
+	if(0 != expected)
+		*expected = encoder->private_->verify.error_stats.expected;
+	if(0 != got)
+		*got = encoder->private_->verify.error_stats.got;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_get_verify(const FLAC__StreamEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	return encoder->protected_->verify;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_get_streamable_subset(const FLAC__StreamEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	return encoder->protected_->streamable_subset;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_get_do_mid_side_stereo(const FLAC__StreamEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	return encoder->protected_->do_mid_side_stereo;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_get_loose_mid_side_stereo(const FLAC__StreamEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	return encoder->protected_->loose_mid_side_stereo;
+}
+
+FLAC_API unsigned FLAC__stream_encoder_get_channels(const FLAC__StreamEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	return encoder->protected_->channels;
+}
+
+FLAC_API unsigned FLAC__stream_encoder_get_bits_per_sample(const FLAC__StreamEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	return encoder->protected_->bits_per_sample;
+}
+
+FLAC_API unsigned FLAC__stream_encoder_get_sample_rate(const FLAC__StreamEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	return encoder->protected_->sample_rate;
+}
+
+FLAC_API unsigned FLAC__stream_encoder_get_blocksize(const FLAC__StreamEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	return encoder->protected_->blocksize;
+}
+
+FLAC_API unsigned FLAC__stream_encoder_get_max_lpc_order(const FLAC__StreamEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	return encoder->protected_->max_lpc_order;
+}
+
+FLAC_API unsigned FLAC__stream_encoder_get_qlp_coeff_precision(const FLAC__StreamEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	return encoder->protected_->qlp_coeff_precision;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_get_do_qlp_coeff_prec_search(const FLAC__StreamEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	return encoder->protected_->do_qlp_coeff_prec_search;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_get_do_escape_coding(const FLAC__StreamEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	return encoder->protected_->do_escape_coding;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_get_do_exhaustive_model_search(const FLAC__StreamEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	return encoder->protected_->do_exhaustive_model_search;
+}
+
+FLAC_API unsigned FLAC__stream_encoder_get_min_residual_partition_order(const FLAC__StreamEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	return encoder->protected_->min_residual_partition_order;
+}
+
+FLAC_API unsigned FLAC__stream_encoder_get_max_residual_partition_order(const FLAC__StreamEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	return encoder->protected_->max_residual_partition_order;
+}
+
+FLAC_API unsigned FLAC__stream_encoder_get_rice_parameter_search_dist(const FLAC__StreamEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	return encoder->protected_->rice_parameter_search_dist;
+}
+
+FLAC_API FLAC__uint64 FLAC__stream_encoder_get_total_samples_estimate(const FLAC__StreamEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	return encoder->protected_->total_samples_estimate;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_process(FLAC__StreamEncoder *encoder, const FLAC__int32 * const buffer[], unsigned samples)
+{
+	unsigned i, j, channel;
+	FLAC__int32 x, mid, side;
+	const unsigned channels = encoder->protected_->channels, blocksize = encoder->protected_->blocksize;
+
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(encoder->protected_->state == FLAC__STREAM_ENCODER_OK);
+
+	j = 0;
+	if(encoder->protected_->do_mid_side_stereo && channels == 2) {
+		do {
+			if(encoder->protected_->verify)
+				append_to_verify_fifo_(&encoder->private_->verify.input_fifo, buffer, j, channels, min(blocksize-encoder->private_->current_sample_number, samples-j));
+
+			for(i = encoder->private_->current_sample_number; i < blocksize && j < samples; i++, j++) {
+				x = mid = side = buffer[0][j];
+				encoder->private_->integer_signal[0][i] = x;
+				encoder->private_->real_signal[0][i] = (FLAC__real)x;
+				x = buffer[1][j];
+				encoder->private_->integer_signal[1][i] = x;
+				encoder->private_->real_signal[1][i] = (FLAC__real)x;
+				mid += x;
+				side -= x;
+				mid >>= 1; /* NOTE: not the same as 'mid = (buffer[0][j] + buffer[1][j]) / 2' ! */
+				encoder->private_->integer_signal_mid_side[1][i] = side;
+				encoder->private_->integer_signal_mid_side[0][i] = mid;
+				encoder->private_->real_signal_mid_side[1][i] = (FLAC__real)side;
+				encoder->private_->real_signal_mid_side[0][i] = (FLAC__real)mid;
+				encoder->private_->current_sample_number++;
+			}
+			if(i == blocksize) {
+				if(!process_frame_(encoder, false)) /* false => not last frame */
+					return false;
+			}
+		} while(j < samples);
+	}
+	else {
+		do {
+			if(encoder->protected_->verify)
+				append_to_verify_fifo_(&encoder->private_->verify.input_fifo, buffer, j, channels, min(blocksize-encoder->private_->current_sample_number, samples-j));
+
+			for(i = encoder->private_->current_sample_number; i < blocksize && j < samples; i++, j++) {
+				for(channel = 0; channel < channels; channel++) {
+					x = buffer[channel][j];
+					encoder->private_->integer_signal[channel][i] = x;
+					encoder->private_->real_signal[channel][i] = (FLAC__real)x;
+				}
+				encoder->private_->current_sample_number++;
+			}
+			if(i == blocksize) {
+				if(!process_frame_(encoder, false)) /* false => not last frame */
+					return false;
+			}
+		} while(j < samples);
+	}
+
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_process_interleaved(FLAC__StreamEncoder *encoder, const FLAC__int32 buffer[], unsigned samples)
+{
+	unsigned i, j, k, channel;
+	FLAC__int32 x, mid, side;
+	const unsigned channels = encoder->protected_->channels, blocksize = encoder->protected_->blocksize;
+
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(encoder->protected_->state == FLAC__STREAM_ENCODER_OK);
+
+	j = k = 0;
+	if(encoder->protected_->do_mid_side_stereo && channels == 2) {
+		do {
+			if(encoder->protected_->verify)
+				append_to_verify_fifo_interleaved_(&encoder->private_->verify.input_fifo, buffer, j, channels, min(blocksize-encoder->private_->current_sample_number, samples-j));
+
+			for(i = encoder->private_->current_sample_number; i < blocksize && j < samples; i++, j++) {
+				x = mid = side = buffer[k++];
+				encoder->private_->integer_signal[0][i] = x;
+				encoder->private_->real_signal[0][i] = (FLAC__real)x;
+				x = buffer[k++];
+				encoder->private_->integer_signal[1][i] = x;
+				encoder->private_->real_signal[1][i] = (FLAC__real)x;
+				mid += x;
+				side -= x;
+				mid >>= 1; /* NOTE: not the same as 'mid = (left + right) / 2' ! */
+				encoder->private_->integer_signal_mid_side[1][i] = side;
+				encoder->private_->integer_signal_mid_side[0][i] = mid;
+				encoder->private_->real_signal_mid_side[1][i] = (FLAC__real)side;
+				encoder->private_->real_signal_mid_side[0][i] = (FLAC__real)mid;
+				encoder->private_->current_sample_number++;
+			}
+			if(i == blocksize) {
+				if(!process_frame_(encoder, false)) /* false => not last frame */
+					return false;
+			}
+		} while(j < samples);
+	}
+	else {
+		do {
+			if(encoder->protected_->verify)
+				append_to_verify_fifo_interleaved_(&encoder->private_->verify.input_fifo, buffer, j, channels, min(blocksize-encoder->private_->current_sample_number, samples-j));
+
+			for(i = encoder->private_->current_sample_number; i < blocksize && j < samples; i++, j++) {
+				for(channel = 0; channel < channels; channel++) {
+					x = buffer[k++];
+					encoder->private_->integer_signal[channel][i] = x;
+					encoder->private_->real_signal[channel][i] = (FLAC__real)x;
+				}
+				encoder->private_->current_sample_number++;
+			}
+			if(i == blocksize) {
+				if(!process_frame_(encoder, false)) /* false => not last frame */
+					return false;
+			}
+		} while(j < samples);
+	}
+
+	return true;
+}
+
+/***********************************************************************
+ *
+ * Private class methods
+ *
+ ***********************************************************************/
+
+void set_defaults_(FLAC__StreamEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+
+	encoder->protected_->verify = false;
+	encoder->protected_->streamable_subset = true;
+	encoder->protected_->do_mid_side_stereo = false;
+	encoder->protected_->loose_mid_side_stereo = false;
+	encoder->protected_->channels = 2;
+	encoder->protected_->bits_per_sample = 16;
+	encoder->protected_->sample_rate = 44100;
+	encoder->protected_->blocksize = 1152;
+	encoder->protected_->max_lpc_order = 0;
+	encoder->protected_->qlp_coeff_precision = 0;
+	encoder->protected_->do_qlp_coeff_prec_search = false;
+	encoder->protected_->do_exhaustive_model_search = false;
+	encoder->protected_->do_escape_coding = false;
+	encoder->protected_->min_residual_partition_order = 0;
+	encoder->protected_->max_residual_partition_order = 0;
+	encoder->protected_->rice_parameter_search_dist = 0;
+	encoder->protected_->total_samples_estimate = 0;
+	encoder->protected_->metadata = 0;
+	encoder->protected_->num_metadata_blocks = 0;
+
+	encoder->private_->disable_constant_subframes = false;
+	encoder->private_->disable_fixed_subframes = false;
+	encoder->private_->disable_verbatim_subframes = false;
+	encoder->private_->write_callback = 0;
+	encoder->private_->metadata_callback = 0;
+	encoder->private_->client_data = 0;
+}
+
+void free_(FLAC__StreamEncoder *encoder)
+{
+	unsigned i, channel;
+
+	FLAC__ASSERT(0 != encoder);
+	for(i = 0; i < encoder->protected_->channels; i++) {
+		if(0 != encoder->private_->integer_signal_unaligned[i]) {
+			free(encoder->private_->integer_signal_unaligned[i]);
+			encoder->private_->integer_signal_unaligned[i] = 0;
+		}
+		if(0 != encoder->private_->real_signal_unaligned[i]) {
+			free(encoder->private_->real_signal_unaligned[i]);
+			encoder->private_->real_signal_unaligned[i] = 0;
+		}
+	}
+	for(i = 0; i < 2; i++) {
+		if(0 != encoder->private_->integer_signal_mid_side_unaligned[i]) {
+			free(encoder->private_->integer_signal_mid_side_unaligned[i]);
+			encoder->private_->integer_signal_mid_side_unaligned[i] = 0;
+		}
+		if(0 != encoder->private_->real_signal_mid_side_unaligned[i]) {
+			free(encoder->private_->real_signal_mid_side_unaligned[i]);
+			encoder->private_->real_signal_mid_side_unaligned[i] = 0;
+		}
+	}
+	for(channel = 0; channel < encoder->protected_->channels; channel++) {
+		for(i = 0; i < 2; i++) {
+			if(0 != encoder->private_->residual_workspace_unaligned[channel][i]) {
+				free(encoder->private_->residual_workspace_unaligned[channel][i]);
+				encoder->private_->residual_workspace_unaligned[channel][i] = 0;
+			}
+		}
+	}
+	for(channel = 0; channel < 2; channel++) {
+		for(i = 0; i < 2; i++) {
+			if(0 != encoder->private_->residual_workspace_mid_side_unaligned[channel][i]) {
+				free(encoder->private_->residual_workspace_mid_side_unaligned[channel][i]);
+				encoder->private_->residual_workspace_mid_side_unaligned[channel][i] = 0;
+			}
+		}
+	}
+	if(0 != encoder->private_->abs_residual_unaligned) {
+		free(encoder->private_->abs_residual_unaligned);
+		encoder->private_->abs_residual_unaligned = 0;
+	}
+	if(0 != encoder->private_->abs_residual_partition_sums_unaligned) {
+		free(encoder->private_->abs_residual_partition_sums_unaligned);
+		encoder->private_->abs_residual_partition_sums_unaligned = 0;
+	}
+	if(0 != encoder->private_->raw_bits_per_partition_unaligned) {
+		free(encoder->private_->raw_bits_per_partition_unaligned);
+		encoder->private_->raw_bits_per_partition_unaligned = 0;
+	}
+	if(encoder->protected_->verify) {
+		for(i = 0; i < encoder->protected_->channels; i++) {
+			if(0 != encoder->private_->verify.input_fifo.data[i]) {
+				free(encoder->private_->verify.input_fifo.data[i]);
+				encoder->private_->verify.input_fifo.data[i] = 0;
+			}
+		}
+	}
+	FLAC__bitbuffer_free(encoder->private_->frame);
+}
+
+FLAC__bool resize_buffers_(FLAC__StreamEncoder *encoder, unsigned new_size)
+{
+	FLAC__bool ok;
+	unsigned i, channel;
+
+	FLAC__ASSERT(new_size > 0);
+	FLAC__ASSERT(encoder->protected_->state == FLAC__STREAM_ENCODER_OK);
+	FLAC__ASSERT(encoder->private_->current_sample_number == 0);
+
+	/* To avoid excessive malloc'ing, we only grow the buffer; no shrinking. */
+	if(new_size <= encoder->private_->input_capacity)
+		return true;
+
+	ok = true;
+
+	/* WATCHOUT: FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32_mmx()
+	 * requires that the input arrays (in our case the integer signals)
+	 * have a buffer of up to 3 zeroes in front (at negative indices) for
+	 * alignment purposes; we use 4 to keep the data well-aligned.
+	 */
+
+	for(i = 0; ok && i < encoder->protected_->channels; i++) {
+		ok = ok && FLAC__memory_alloc_aligned_int32_array(new_size+4, &encoder->private_->integer_signal_unaligned[i], &encoder->private_->integer_signal[i]);
+		ok = ok && FLAC__memory_alloc_aligned_real_array(new_size, &encoder->private_->real_signal_unaligned[i], &encoder->private_->real_signal[i]);
+		memset(encoder->private_->integer_signal[i], 0, sizeof(FLAC__int32)*4);
+		encoder->private_->integer_signal[i] += 4;
+	}
+	for(i = 0; ok && i < 2; i++) {
+		ok = ok && FLAC__memory_alloc_aligned_int32_array(new_size+4, &encoder->private_->integer_signal_mid_side_unaligned[i], &encoder->private_->integer_signal_mid_side[i]);
+		ok = ok && FLAC__memory_alloc_aligned_real_array(new_size, &encoder->private_->real_signal_mid_side_unaligned[i], &encoder->private_->real_signal_mid_side[i]);
+		memset(encoder->private_->integer_signal_mid_side[i], 0, sizeof(FLAC__int32)*4);
+		encoder->private_->integer_signal_mid_side[i] += 4;
+	}
+	for(channel = 0; ok && channel < encoder->protected_->channels; channel++) {
+		for(i = 0; ok && i < 2; i++) {
+			ok = ok && FLAC__memory_alloc_aligned_int32_array(new_size, &encoder->private_->residual_workspace_unaligned[channel][i], &encoder->private_->residual_workspace[channel][i]);
+		}
+	}
+	for(channel = 0; ok && channel < 2; channel++) {
+		for(i = 0; ok && i < 2; i++) {
+			ok = ok && FLAC__memory_alloc_aligned_int32_array(new_size, &encoder->private_->residual_workspace_mid_side_unaligned[channel][i], &encoder->private_->residual_workspace_mid_side[channel][i]);
+		}
+	}
+	ok = ok && FLAC__memory_alloc_aligned_uint32_array(new_size, &encoder->private_->abs_residual_unaligned, &encoder->private_->abs_residual);
+	if(encoder->private_->precompute_partition_sums || encoder->protected_->do_escape_coding) /* we require precompute_partition_sums if do_escape_coding because of their intertwined nature */
+		ok = ok && FLAC__memory_alloc_aligned_uint64_array(new_size * 2, &encoder->private_->abs_residual_partition_sums_unaligned, &encoder->private_->abs_residual_partition_sums);
+	if(encoder->protected_->do_escape_coding)
+		ok = ok && FLAC__memory_alloc_aligned_unsigned_array(new_size * 2, &encoder->private_->raw_bits_per_partition_unaligned, &encoder->private_->raw_bits_per_partition);
+
+	if(ok)
+		encoder->private_->input_capacity = new_size;
+	else
+		encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR;
+
+	return ok;
+}
+
+FLAC__bool write_bitbuffer_(FLAC__StreamEncoder *encoder, unsigned samples)
+{
+	const FLAC__byte *buffer;
+	unsigned bytes;
+
+	FLAC__ASSERT(FLAC__bitbuffer_is_byte_aligned(encoder->private_->frame));
+
+	FLAC__bitbuffer_get_buffer(encoder->private_->frame, &buffer, &bytes);
+
+	if(encoder->protected_->verify) {
+		encoder->private_->verify.output.data = buffer;
+		encoder->private_->verify.output.bytes = bytes;
+		if(encoder->private_->verify.state_hint == ENCODER_IN_MAGIC) {
+			encoder->private_->verify.needs_magic_hack = true;
+		}
+		else {
+			if(!FLAC__stream_decoder_process_single(encoder->private_->verify.decoder)) {
+				FLAC__bitbuffer_release_buffer(encoder->private_->frame);
+				if(encoder->protected_->state != FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA)
+					encoder->protected_->state = FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR;
+				return false;
+			}
+		}
+	}
+
+	if(encoder->private_->write_callback(encoder, buffer, bytes, samples, encoder->private_->current_frame_number, encoder->private_->client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) {
+		FLAC__bitbuffer_release_buffer(encoder->private_->frame);
+		encoder->protected_->state = FLAC__STREAM_ENCODER_FATAL_ERROR_WHILE_WRITING;
+		return false;
+	}
+
+	FLAC__bitbuffer_release_buffer(encoder->private_->frame);
+
+	if(samples > 0) {
+		encoder->private_->metadata.data.stream_info.min_framesize = min(bytes, encoder->private_->metadata.data.stream_info.min_framesize);
+		encoder->private_->metadata.data.stream_info.max_framesize = max(bytes, encoder->private_->metadata.data.stream_info.max_framesize);
+	}
+
+	return true;
+}
+
+FLAC__bool process_frame_(FLAC__StreamEncoder *encoder, FLAC__bool is_last_frame)
+{
+	FLAC__ASSERT(encoder->protected_->state == FLAC__STREAM_ENCODER_OK);
+
+	/*
+	 * Accumulate raw signal to the MD5 signature
+	 */
+	if(!FLAC__MD5Accumulate(&encoder->private_->md5context, (const FLAC__int32 * const *)encoder->private_->integer_signal, encoder->protected_->channels, encoder->protected_->blocksize, (encoder->protected_->bits_per_sample+7) / 8)) {
+		encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR;
+		return false;
+	}
+
+	/*
+	 * Process the frame header and subframes into the frame bitbuffer
+	 */
+	if(!process_subframes_(encoder, is_last_frame)) {
+		/* the above function sets the state for us in case of an error */
+		return false;
+	}
+
+	/*
+	 * Zero-pad the frame to a byte_boundary
+	 */
+	if(!FLAC__bitbuffer_zero_pad_to_byte_boundary(encoder->private_->frame)) {
+		encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR;
+		return false;
+	}
+
+	/*
+	 * CRC-16 the whole thing
+	 */
+	FLAC__ASSERT(FLAC__bitbuffer_is_byte_aligned(encoder->private_->frame));
+	FLAC__bitbuffer_write_raw_uint32(encoder->private_->frame, FLAC__bitbuffer_get_write_crc16(encoder->private_->frame), FLAC__FRAME_FOOTER_CRC_LEN);
+
+	/*
+	 * Write it
+	 */
+	if(!write_bitbuffer_(encoder, encoder->protected_->blocksize)) {
+		/* the above function sets the state for us in case of an error */
+		return false;
+	}
+
+	/*
+	 * Get ready for the next frame
+	 */
+	encoder->private_->current_sample_number = 0;
+	encoder->private_->current_frame_number++;
+	encoder->private_->metadata.data.stream_info.total_samples += (FLAC__uint64)encoder->protected_->blocksize;
+
+	return true;
+}
+
+FLAC__bool process_subframes_(FLAC__StreamEncoder *encoder, FLAC__bool is_last_frame)
+{
+	FLAC__FrameHeader frame_header;
+	unsigned channel, min_partition_order = encoder->protected_->min_residual_partition_order, max_partition_order;
+	FLAC__bool do_independent, do_mid_side, precompute_partition_sums;
+
+	/*
+	 * Calculate the min,max Rice partition orders
+	 */
+	if(is_last_frame) {
+		max_partition_order = 0;
+	}
+	else {
+		max_partition_order = FLAC__format_get_max_rice_partition_order_from_blocksize(encoder->protected_->blocksize);
+		max_partition_order = min(max_partition_order, encoder->protected_->max_residual_partition_order);
+	}
+	min_partition_order = min(min_partition_order, max_partition_order);
+
+	precompute_partition_sums = encoder->private_->precompute_partition_sums && ((max_partition_order > min_partition_order) || encoder->protected_->do_escape_coding);
+
+	/*
+	 * Setup the frame
+	 */
+	if(!FLAC__bitbuffer_clear(encoder->private_->frame)) {
+		encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR;
+		return false;
+	}
+	frame_header.blocksize = encoder->protected_->blocksize;
+	frame_header.sample_rate = encoder->protected_->sample_rate;
+	frame_header.channels = encoder->protected_->channels;
+	frame_header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT; /* the default unless the encoder determines otherwise */
+	frame_header.bits_per_sample = encoder->protected_->bits_per_sample;
+	frame_header.number_type = FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER;
+	frame_header.number.frame_number = encoder->private_->current_frame_number;
+
+	/*
+	 * Figure out what channel assignments to try
+	 */
+	if(encoder->protected_->do_mid_side_stereo) {
+		if(encoder->protected_->loose_mid_side_stereo) {
+			if(encoder->private_->loose_mid_side_stereo_frame_count == 0) {
+				do_independent = true;
+				do_mid_side = true;
+			}
+			else {
+				do_independent = (encoder->private_->last_channel_assignment == FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT);
+				do_mid_side = !do_independent;
+			}
+		}
+		else {
+			do_independent = true;
+			do_mid_side = true;
+		}
+	}
+	else {
+		do_independent = true;
+		do_mid_side = false;
+	}
+
+	FLAC__ASSERT(do_independent || do_mid_side);
+
+	/*
+	 * Check for wasted bits; set effective bps for each subframe
+	 */
+	if(do_independent) {
+		for(channel = 0; channel < encoder->protected_->channels; channel++) {
+			const unsigned w = get_wasted_bits_(encoder->private_->integer_signal[channel], encoder->protected_->blocksize);
+			encoder->private_->subframe_workspace[channel][0].wasted_bits = encoder->private_->subframe_workspace[channel][1].wasted_bits = w;
+			encoder->private_->subframe_bps[channel] = encoder->protected_->bits_per_sample - w;
+		}
+	}
+	if(do_mid_side) {
+		FLAC__ASSERT(encoder->protected_->channels == 2);
+		for(channel = 0; channel < 2; channel++) {
+			const unsigned w = get_wasted_bits_(encoder->private_->integer_signal_mid_side[channel], encoder->protected_->blocksize);
+			encoder->private_->subframe_workspace_mid_side[channel][0].wasted_bits = encoder->private_->subframe_workspace_mid_side[channel][1].wasted_bits = w;
+			encoder->private_->subframe_bps_mid_side[channel] = encoder->protected_->bits_per_sample - w + (channel==0? 0:1);
+		}
+	}
+
+	/*
+	 * First do a normal encoding pass of each independent channel
+	 */
+	if(do_independent) {
+		for(channel = 0; channel < encoder->protected_->channels; channel++) {
+			if(!
+				process_subframe_(
+					encoder,
+					min_partition_order,
+					max_partition_order,
+					precompute_partition_sums,
+					&frame_header,
+					encoder->private_->subframe_bps[channel],
+					encoder->private_->integer_signal[channel],
+					encoder->private_->real_signal[channel],
+					encoder->private_->subframe_workspace_ptr[channel],
+					encoder->private_->partitioned_rice_contents_workspace_ptr[channel],
+					encoder->private_->residual_workspace[channel],
+					encoder->private_->best_subframe+channel,
+					encoder->private_->best_subframe_bits+channel
+				)
+			)
+				return false;
+		}
+	}
+
+	/*
+	 * Now do mid and side channels if requested
+	 */
+	if(do_mid_side) {
+		FLAC__ASSERT(encoder->protected_->channels == 2);
+
+		for(channel = 0; channel < 2; channel++) {
+			if(!
+				process_subframe_(
+					encoder,
+					min_partition_order,
+					max_partition_order,
+					precompute_partition_sums,
+					&frame_header,
+					encoder->private_->subframe_bps_mid_side[channel],
+					encoder->private_->integer_signal_mid_side[channel],
+					encoder->private_->real_signal_mid_side[channel],
+					encoder->private_->subframe_workspace_ptr_mid_side[channel],
+					encoder->private_->partitioned_rice_contents_workspace_ptr_mid_side[channel],
+					encoder->private_->residual_workspace_mid_side[channel],
+					encoder->private_->best_subframe_mid_side+channel,
+					encoder->private_->best_subframe_bits_mid_side+channel
+				)
+			)
+				return false;
+		}
+	}
+
+	/*
+	 * Compose the frame bitbuffer
+	 */
+	if(do_mid_side) {
+		unsigned left_bps = 0, right_bps = 0; /* initialized only to prevent superfluous compiler warning */
+		FLAC__Subframe *left_subframe = 0, *right_subframe = 0; /* initialized only to prevent superfluous compiler warning */
+		FLAC__ChannelAssignment channel_assignment;
+
+		FLAC__ASSERT(encoder->protected_->channels == 2);
+
+		if(encoder->protected_->loose_mid_side_stereo && encoder->private_->loose_mid_side_stereo_frame_count > 0) {
+			channel_assignment = (encoder->private_->last_channel_assignment == FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT? FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT : FLAC__CHANNEL_ASSIGNMENT_MID_SIDE);
+		}
+		else {
+			unsigned bits[4]; /* WATCHOUT - indexed by FLAC__ChannelAssignment */
+			unsigned min_bits;
+			FLAC__ChannelAssignment ca;
+
+			FLAC__ASSERT(do_independent && do_mid_side);
+
+			/* We have to figure out which channel assignent results in the smallest frame */
+			bits[FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT] = encoder->private_->best_subframe_bits         [0] + encoder->private_->best_subframe_bits         [1];
+			bits[FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE  ] = encoder->private_->best_subframe_bits         [0] + encoder->private_->best_subframe_bits_mid_side[1];
+			bits[FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE ] = encoder->private_->best_subframe_bits         [1] + encoder->private_->best_subframe_bits_mid_side[1];
+			bits[FLAC__CHANNEL_ASSIGNMENT_MID_SIDE   ] = encoder->private_->best_subframe_bits_mid_side[0] + encoder->private_->best_subframe_bits_mid_side[1];
+
+			for(channel_assignment = (FLAC__ChannelAssignment)0, min_bits = bits[0], ca = (FLAC__ChannelAssignment)1; (int)ca <= 3; ca = (FLAC__ChannelAssignment)((int)ca + 1)) {
+				if(bits[ca] < min_bits) {
+					min_bits = bits[ca];
+					channel_assignment = ca;
+				}
+			}
+		}
+
+		frame_header.channel_assignment = channel_assignment;
+
+		if(!FLAC__frame_add_header(&frame_header, encoder->protected_->streamable_subset, encoder->private_->frame)) {
+			encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR;
+			return false;
+		}
+
+		switch(channel_assignment) {
+			case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT:
+				left_subframe  = &encoder->private_->subframe_workspace         [0][encoder->private_->best_subframe         [0]];
+				right_subframe = &encoder->private_->subframe_workspace         [1][encoder->private_->best_subframe         [1]];
+				break;
+			case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE:
+				left_subframe  = &encoder->private_->subframe_workspace         [0][encoder->private_->best_subframe         [0]];
+				right_subframe = &encoder->private_->subframe_workspace_mid_side[1][encoder->private_->best_subframe_mid_side[1]];
+				break;
+			case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE:
+				left_subframe  = &encoder->private_->subframe_workspace_mid_side[1][encoder->private_->best_subframe_mid_side[1]];
+				right_subframe = &encoder->private_->subframe_workspace         [1][encoder->private_->best_subframe         [1]];
+				break;
+			case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE:
+				left_subframe  = &encoder->private_->subframe_workspace_mid_side[0][encoder->private_->best_subframe_mid_side[0]];
+				right_subframe = &encoder->private_->subframe_workspace_mid_side[1][encoder->private_->best_subframe_mid_side[1]];
+				break;
+			default:
+				FLAC__ASSERT(0);
+		}
+
+		switch(channel_assignment) {
+			case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT:
+				left_bps  = encoder->private_->subframe_bps         [0];
+				right_bps = encoder->private_->subframe_bps         [1];
+				break;
+			case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE:
+				left_bps  = encoder->private_->subframe_bps         [0];
+				right_bps = encoder->private_->subframe_bps_mid_side[1];
+				break;
+			case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE:
+				left_bps  = encoder->private_->subframe_bps_mid_side[1];
+				right_bps = encoder->private_->subframe_bps         [1];
+				break;
+			case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE:
+				left_bps  = encoder->private_->subframe_bps_mid_side[0];
+				right_bps = encoder->private_->subframe_bps_mid_side[1];
+				break;
+			default:
+				FLAC__ASSERT(0);
+		}
+
+		/* note that encoder_add_subframe_ sets the state for us in case of an error */
+		if(!add_subframe_(encoder, &frame_header, left_bps , left_subframe , encoder->private_->frame))
+			return false;
+		if(!add_subframe_(encoder, &frame_header, right_bps, right_subframe, encoder->private_->frame))
+			return false;
+	}
+	else {
+		if(!FLAC__frame_add_header(&frame_header, encoder->protected_->streamable_subset, encoder->private_->frame)) {
+			encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR;
+			return false;
+		}
+
+		for(channel = 0; channel < encoder->protected_->channels; channel++) {
+			if(!add_subframe_(encoder, &frame_header, encoder->private_->subframe_bps[channel], &encoder->private_->subframe_workspace[channel][encoder->private_->best_subframe[channel]], encoder->private_->frame)) {
+				/* the above function sets the state for us in case of an error */
+				return false;
+			}
+		}
+	}
+
+	if(encoder->protected_->loose_mid_side_stereo) {
+		encoder->private_->loose_mid_side_stereo_frame_count++;
+		if(encoder->private_->loose_mid_side_stereo_frame_count >= encoder->private_->loose_mid_side_stereo_frames)
+			encoder->private_->loose_mid_side_stereo_frame_count = 0;
+	}
+
+	encoder->private_->last_channel_assignment = frame_header.channel_assignment;
+
+	return true;
+}
+
+FLAC__bool process_subframe_(
+	FLAC__StreamEncoder *encoder,
+	unsigned min_partition_order,
+	unsigned max_partition_order,
+	FLAC__bool precompute_partition_sums,
+	const FLAC__FrameHeader *frame_header,
+	unsigned subframe_bps,
+	const FLAC__int32 integer_signal[],
+	const FLAC__real real_signal[],
+	FLAC__Subframe *subframe[2],
+	FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents[2],
+	FLAC__int32 *residual[2],
+	unsigned *best_subframe,
+	unsigned *best_bits
+)
+{
+	FLAC__real fixed_residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1];
+	FLAC__real lpc_residual_bits_per_sample;
+	FLAC__real autoc[FLAC__MAX_LPC_ORDER+1]; /* WATCHOUT: the size is important even though encoder->protected_->max_lpc_order might be less; some asm routines need all the space */
+	FLAC__real lpc_error[FLAC__MAX_LPC_ORDER];
+	unsigned min_lpc_order, max_lpc_order, lpc_order;
+	unsigned min_fixed_order, max_fixed_order, guess_fixed_order, fixed_order;
+	unsigned min_qlp_coeff_precision, max_qlp_coeff_precision, qlp_coeff_precision;
+	unsigned rice_parameter;
+	unsigned _candidate_bits, _best_bits;
+	unsigned _best_subframe;
+
+	/* verbatim subframe is the baseline against which we measure other compressed subframes */
+	_best_subframe = 0;
+	if(encoder->private_->disable_verbatim_subframes && frame_header->blocksize >= FLAC__MAX_FIXED_ORDER)
+		_best_bits = UINT_MAX;
+	else
+		_best_bits = evaluate_verbatim_subframe_(integer_signal, frame_header->blocksize, subframe_bps, subframe[_best_subframe]);
+
+	if(frame_header->blocksize >= FLAC__MAX_FIXED_ORDER) {
+		unsigned signal_is_constant = false;
+		guess_fixed_order = encoder->private_->local_fixed_compute_best_predictor(integer_signal+FLAC__MAX_FIXED_ORDER, frame_header->blocksize-FLAC__MAX_FIXED_ORDER, fixed_residual_bits_per_sample);
+		/* check for constant subframe */
+		if(!encoder->private_->disable_constant_subframes && fixed_residual_bits_per_sample[1] == 0.0) {
+			/* the above means integer_signal+FLAC__MAX_FIXED_ORDER is constant, now we just have to check the warmup samples */
+			unsigned i;
+			signal_is_constant = true;
+			for(i = 1; i <= FLAC__MAX_FIXED_ORDER; i++) {
+				if(integer_signal[0] != integer_signal[i]) {
+					signal_is_constant = false;
+					break;
+				}
+			}
+		}
+		if(signal_is_constant) {
+			_candidate_bits = evaluate_constant_subframe_(integer_signal[0], subframe_bps, subframe[!_best_subframe]);
+			if(_candidate_bits < _best_bits) {
+				_best_subframe = !_best_subframe;
+				_best_bits = _candidate_bits;
+			}
+		}
+		else {
+			if(!encoder->private_->disable_fixed_subframes || (encoder->protected_->max_lpc_order == 0 && _best_bits == UINT_MAX)) {
+				/* encode fixed */
+				if(encoder->protected_->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] >= (FLAC__real)subframe_bps)
+						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; /* 0.5 is for rounding */
+#ifndef FLAC__SYMMETRIC_RICE
+					rice_parameter++; /* to account for the signed->unsigned conversion during rice coding */
+#endif
+					if(rice_parameter >= FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER) {
+#ifdef DEBUG_VERBOSE
+						fprintf(stderr, "clipping rice_parameter (%u -> %u) @0\n", rice_parameter, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1);
+#endif
+						rice_parameter = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1;
+					}
+					_candidate_bits =
+						evaluate_fixed_subframe_(
+							encoder,
+							integer_signal,
+							residual[!_best_subframe],
+							encoder->private_->abs_residual,
+							encoder->private_->abs_residual_partition_sums,
+							encoder->private_->raw_bits_per_partition,
+							frame_header->blocksize,
+							subframe_bps,
+							fixed_order,
+							rice_parameter,
+							min_partition_order,
+							max_partition_order,
+							precompute_partition_sums,
+							encoder->protected_->do_escape_coding,
+							encoder->protected_->rice_parameter_search_dist,
+							subframe[!_best_subframe],
+							partitioned_rice_contents[!_best_subframe]
+						);
+					if(_candidate_bits < _best_bits) {
+						_best_subframe = !_best_subframe;
+						_best_bits = _candidate_bits;
+					}
+				}
+			}
+
+			/* encode lpc */
+			if(encoder->protected_->max_lpc_order > 0) {
+				if(encoder->protected_->max_lpc_order >= frame_header->blocksize)
+					max_lpc_order = frame_header->blocksize-1;
+				else
+					max_lpc_order = encoder->protected_->max_lpc_order;
+				if(max_lpc_order > 0) {
+					encoder->private_->local_lpc_compute_autocorrelation(real_signal, frame_header->blocksize, max_lpc_order+1, autoc);
+					/* if autoc[0] == 0.0, the signal is constant and we usually won't get here, but it can happen */
+					if(autoc[0] != 0.0) {
+						FLAC__lpc_compute_lp_coefficients(autoc, max_lpc_order, encoder->private_->lp_coeff, lpc_error);
+						if(encoder->protected_->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, subframe_bps);
+							min_lpc_order = max_lpc_order = guess_lpc_order;
+						}
+						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-lpc_order);
+							if(lpc_residual_bits_per_sample >= (FLAC__real)subframe_bps)
+								continue; /* don't even try */
+							rice_parameter = (lpc_residual_bits_per_sample > 0.0)? (unsigned)(lpc_residual_bits_per_sample+0.5) : 0; /* 0.5 is for rounding */
+#ifndef FLAC__SYMMETRIC_RICE
+							rice_parameter++; /* to account for the signed->unsigned conversion during rice coding */
+#endif
+							if(rice_parameter >= FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER) {
+#ifdef DEBUG_VERBOSE
+								fprintf(stderr, "clipping rice_parameter (%u -> %u) @1\n", rice_parameter, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1);
+#endif
+								rice_parameter = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1;
+							}
+							if(encoder->protected_->do_qlp_coeff_prec_search) {
+								min_qlp_coeff_precision = FLAC__MIN_QLP_COEFF_PRECISION;
+								/* ensure a 32-bit datapath throughout for 16bps or less */
+								if(subframe_bps <= 16)
+									max_qlp_coeff_precision = min(32 - subframe_bps - lpc_order, FLAC__MAX_QLP_COEFF_PRECISION);
+								else
+									max_qlp_coeff_precision = FLAC__MAX_QLP_COEFF_PRECISION;
+							}
+							else {
+								min_qlp_coeff_precision = max_qlp_coeff_precision = encoder->protected_->qlp_coeff_precision;
+							}
+							for(qlp_coeff_precision = min_qlp_coeff_precision; qlp_coeff_precision <= max_qlp_coeff_precision; qlp_coeff_precision++) {
+								_candidate_bits =
+									evaluate_lpc_subframe_(
+										encoder,
+										integer_signal,
+										residual[!_best_subframe],
+										encoder->private_->abs_residual,
+										encoder->private_->abs_residual_partition_sums,
+										encoder->private_->raw_bits_per_partition,
+										encoder->private_->lp_coeff[lpc_order-1],
+										frame_header->blocksize,
+										subframe_bps,
+										lpc_order,
+										qlp_coeff_precision,
+										rice_parameter,
+										min_partition_order,
+										max_partition_order,
+										precompute_partition_sums,
+										encoder->protected_->do_escape_coding,
+										encoder->protected_->rice_parameter_search_dist,
+										subframe[!_best_subframe],
+										partitioned_rice_contents[!_best_subframe]
+									);
+								if(_candidate_bits > 0) { /* if == 0, there was a problem quantizing the lpcoeffs */
+									if(_candidate_bits < _best_bits) {
+										_best_subframe = !_best_subframe;
+										_best_bits = _candidate_bits;
+									}
+								}
+							}
+						}
+					}
+				}
+			}
+		}
+	}
+
+	/* under rare circumstances this can happen when all but lpc subframe types are disabled: */
+	if(_best_bits == UINT_MAX) {
+		FLAC__ASSERT(_best_subframe == 0);
+		_best_bits = evaluate_verbatim_subframe_(integer_signal, frame_header->blocksize, subframe_bps, subframe[_best_subframe]);
+	}
+
+	*best_subframe = _best_subframe;
+	*best_bits = _best_bits;
+
+	return true;
+}
+
+FLAC__bool add_subframe_(
+	FLAC__StreamEncoder *encoder,
+	const FLAC__FrameHeader *frame_header,
+	unsigned subframe_bps,
+	const FLAC__Subframe *subframe,
+	FLAC__BitBuffer *frame
+)
+{
+	switch(subframe->type) {
+		case FLAC__SUBFRAME_TYPE_CONSTANT:
+			if(!FLAC__subframe_add_constant(&(subframe->data.constant), subframe_bps, subframe->wasted_bits, frame)) {
+				encoder->protected_->state = FLAC__STREAM_ENCODER_FATAL_ERROR_WHILE_ENCODING;
+				return false;
+			}
+			break;
+		case FLAC__SUBFRAME_TYPE_FIXED:
+			if(!FLAC__subframe_add_fixed(&(subframe->data.fixed), frame_header->blocksize - subframe->data.fixed.order, subframe_bps, subframe->wasted_bits, frame)) {
+				encoder->protected_->state = FLAC__STREAM_ENCODER_FATAL_ERROR_WHILE_ENCODING;
+				return false;
+			}
+			break;
+		case FLAC__SUBFRAME_TYPE_LPC:
+			if(!FLAC__subframe_add_lpc(&(subframe->data.lpc), frame_header->blocksize - subframe->data.lpc.order, subframe_bps, subframe->wasted_bits, frame)) {
+				encoder->protected_->state = FLAC__STREAM_ENCODER_FATAL_ERROR_WHILE_ENCODING;
+				return false;
+			}
+			break;
+		case FLAC__SUBFRAME_TYPE_VERBATIM:
+			if(!FLAC__subframe_add_verbatim(&(subframe->data.verbatim), frame_header->blocksize, subframe_bps, subframe->wasted_bits, frame)) {
+				encoder->protected_->state = FLAC__STREAM_ENCODER_FATAL_ERROR_WHILE_ENCODING;
+				return false;
+			}
+			break;
+		default:
+			FLAC__ASSERT(0);
+	}
+
+	return true;
+}
+
+unsigned evaluate_constant_subframe_(
+	const FLAC__int32 signal,
+	unsigned subframe_bps,
+	FLAC__Subframe *subframe
+)
+{
+	subframe->type = FLAC__SUBFRAME_TYPE_CONSTANT;
+	subframe->data.constant.value = signal;
+
+	return FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN + subframe_bps;
+}
+
+unsigned evaluate_fixed_subframe_(
+	FLAC__StreamEncoder *encoder,
+	const FLAC__int32 signal[],
+	FLAC__int32 residual[],
+	FLAC__uint32 abs_residual[],
+	FLAC__uint64 abs_residual_partition_sums[],
+	unsigned raw_bits_per_partition[],
+	unsigned blocksize,
+	unsigned subframe_bps,
+	unsigned order,
+	unsigned rice_parameter,
+	unsigned min_partition_order,
+	unsigned max_partition_order,
+	FLAC__bool precompute_partition_sums,
+	FLAC__bool do_escape_coding,
+	unsigned rice_parameter_search_dist,
+	FLAC__Subframe *subframe,
+	FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents
+)
+{
+	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;
+	subframe->data.fixed.entropy_coding_method.data.partitioned_rice.contents = partitioned_rice_contents;
+	subframe->data.fixed.residual = residual;
+
+	residual_bits =
+		find_best_partition_order_(
+			encoder->private_,
+			residual,
+			abs_residual,
+			abs_residual_partition_sums,
+			raw_bits_per_partition,
+			residual_samples,
+			order,
+			rice_parameter,
+			min_partition_order,
+			max_partition_order,
+			precompute_partition_sums,
+			do_escape_coding,
+			rice_parameter_search_dist,
+			&subframe->data.fixed.entropy_coding_method.data.partitioned_rice
+		);
+
+	subframe->data.fixed.order = order;
+	for(i = 0; i < order; i++)
+		subframe->data.fixed.warmup[i] = signal[i];
+
+	return FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN + (order * subframe_bps) + residual_bits;
+}
+
+unsigned evaluate_lpc_subframe_(
+	FLAC__StreamEncoder *encoder,
+	const FLAC__int32 signal[],
+	FLAC__int32 residual[],
+	FLAC__uint32 abs_residual[],
+	FLAC__uint64 abs_residual_partition_sums[],
+	unsigned raw_bits_per_partition[],
+	const FLAC__real lp_coeff[],
+	unsigned blocksize,
+	unsigned subframe_bps,
+	unsigned order,
+	unsigned qlp_coeff_precision,
+	unsigned rice_parameter,
+	unsigned min_partition_order,
+	unsigned max_partition_order,
+	FLAC__bool precompute_partition_sums,
+	FLAC__bool do_escape_coding,
+	unsigned rice_parameter_search_dist,
+	FLAC__Subframe *subframe,
+	FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents
+)
+{
+	FLAC__int32 qlp_coeff[FLAC__MAX_LPC_ORDER];
+	unsigned i, residual_bits;
+	int quantization, ret;
+	const unsigned residual_samples = blocksize - order;
+
+	/* try to keep qlp coeff precision such that only 32-bit math is required for decode of <=16bps streams */
+	if(subframe_bps <= 16) {
+		FLAC__ASSERT(order > 0);
+		FLAC__ASSERT(order <= FLAC__MAX_LPC_ORDER);
+		qlp_coeff_precision = min(qlp_coeff_precision, 32 - subframe_bps - FLAC__bitmath_ilog2(order));
+	}
+
+	ret = FLAC__lpc_quantize_coefficients(lp_coeff, order, qlp_coeff_precision, 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 */
+
+	if(subframe_bps + qlp_coeff_precision + FLAC__bitmath_ilog2(order) <= 32)
+		if(subframe_bps <= 16 && qlp_coeff_precision <= 16)
+			encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit(signal+order, residual_samples, qlp_coeff, order, quantization, residual);
+		else
+			encoder->private_->local_lpc_compute_residual_from_qlp_coefficients(signal+order, residual_samples, qlp_coeff, order, quantization, residual);
+	else
+		encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_64bit(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;
+	subframe->data.lpc.entropy_coding_method.data.partitioned_rice.contents = partitioned_rice_contents;
+	subframe->data.lpc.residual = residual;
+
+	residual_bits =
+		find_best_partition_order_(
+			encoder->private_,
+			residual,
+			abs_residual,
+			abs_residual_partition_sums,
+			raw_bits_per_partition,
+			residual_samples,
+			order,
+			rice_parameter,
+			min_partition_order,
+			max_partition_order,
+			precompute_partition_sums,
+			do_escape_coding,
+			rice_parameter_search_dist,
+			&subframe->data.fixed.entropy_coding_method.data.partitioned_rice
+		);
+
+	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(FLAC__int32)*FLAC__MAX_LPC_ORDER);
+	for(i = 0; i < order; i++)
+		subframe->data.lpc.warmup[i] = signal[i];
+
+	return FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN + FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN + FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN + (order * (qlp_coeff_precision + subframe_bps)) + residual_bits;
+}
+
+unsigned evaluate_verbatim_subframe_(
+	const FLAC__int32 signal[],
+	unsigned blocksize,
+	unsigned subframe_bps,
+	FLAC__Subframe *subframe
+)
+{
+	subframe->type = FLAC__SUBFRAME_TYPE_VERBATIM;
+
+	subframe->data.verbatim.data = signal;
+
+	return FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN + (blocksize * subframe_bps);
+}
+
+unsigned find_best_partition_order_(
+	FLAC__StreamEncoderPrivate *private_,
+	const FLAC__int32 residual[],
+	FLAC__uint32 abs_residual[],
+	FLAC__uint64 abs_residual_partition_sums[],
+	unsigned raw_bits_per_partition[],
+	unsigned residual_samples,
+	unsigned predictor_order,
+	unsigned rice_parameter,
+	unsigned min_partition_order,
+	unsigned max_partition_order,
+	FLAC__bool precompute_partition_sums,
+	FLAC__bool do_escape_coding,
+	unsigned rice_parameter_search_dist,
+	FLAC__EntropyCodingMethod_PartitionedRice *best_partitioned_rice
+)
+{
+	FLAC__int32 r;
+	unsigned residual_bits, best_residual_bits = 0;
+	unsigned residual_sample;
+	unsigned best_parameters_index = 0;
+	const unsigned blocksize = residual_samples + predictor_order;
+
+	/* compute abs(residual) for use later */
+	for(residual_sample = 0; residual_sample < residual_samples; residual_sample++) {
+		r = residual[residual_sample];
+		abs_residual[residual_sample] = (FLAC__uint32)(r<0? -r : r);
+	}
+
+	max_partition_order = FLAC__format_get_max_rice_partition_order_from_blocksize_limited_max_and_predictor_order(max_partition_order, blocksize, predictor_order);
+	min_partition_order = min(min_partition_order, max_partition_order);
+
+	if(precompute_partition_sums) {
+		int partition_order;
+		unsigned sum;
+
+		precompute_partition_info_sums_(abs_residual, abs_residual_partition_sums, residual_samples, predictor_order, min_partition_order, max_partition_order);
+
+		if(do_escape_coding)
+			precompute_partition_info_escapes_(residual, raw_bits_per_partition, residual_samples, predictor_order, min_partition_order, max_partition_order);
+
+		for(partition_order = (int)max_partition_order, sum = 0; partition_order >= (int)min_partition_order; partition_order--) {
+#ifdef DONT_ESTIMATE_RICE_BITS
+			if(!
+				set_partitioned_rice_with_precompute_(
+					residual,
+					abs_residual_partition_sums+sum,
+					raw_bits_per_partition+sum,
+					residual_samples,
+					predictor_order,
+					rice_parameter,
+					rice_parameter_search_dist,
+					(unsigned)partition_order,
+					do_escape_coding,
+					&private_->partitioned_rice_contents_extra[!best_parameters_index],
+					&residual_bits
+				)
+			)
+#else
+			if(!
+				set_partitioned_rice_with_precompute_(
+					abs_residual,
+					abs_residual_partition_sums+sum,
+					raw_bits_per_partition+sum,
+					residual_samples,
+					predictor_order,
+					rice_parameter,
+					rice_parameter_search_dist,
+					(unsigned)partition_order,
+					do_escape_coding,
+					&private_->partitioned_rice_contents_extra[!best_parameters_index],
+					&residual_bits
+				)
+			)
+#endif
+			{
+				FLAC__ASSERT(best_residual_bits != 0);
+				break;
+			}
+			sum += 1u << partition_order;
+			if(best_residual_bits == 0 || residual_bits < best_residual_bits) {
+				best_residual_bits = residual_bits;
+				best_parameters_index = !best_parameters_index;
+				best_partitioned_rice->order = partition_order;
+			}
+		}
+	}
+	else {
+		unsigned partition_order;
+		for(partition_order = min_partition_order; partition_order <= max_partition_order; partition_order++) {
+#ifdef DONT_ESTIMATE_RICE_BITS
+			if(!
+				set_partitioned_rice_(
+					abs_residual,
+					residual,
+					residual_samples,
+					predictor_order,
+					rice_parameter,
+					rice_parameter_search_dist,
+					partition_order,
+					&private_->partitioned_rice_contents_extra[!best_parameters_index],
+					&residual_bits
+				)
+			)
+#else
+			if(!
+				set_partitioned_rice_(
+					abs_residual,
+					residual_samples,
+					predictor_order,
+					rice_parameter,
+					rice_parameter_search_dist,
+					partition_order,
+					&private_->partitioned_rice_contents_extra[!best_parameters_index],
+					&residual_bits
+				)
+			)
+#endif
+			{
+				FLAC__ASSERT(best_residual_bits != 0);
+				break;
+			}
+			if(best_residual_bits == 0 || residual_bits < best_residual_bits) {
+				best_residual_bits = residual_bits;
+				best_parameters_index = !best_parameters_index;
+				best_partitioned_rice->order = partition_order;
+			}
+		}
+	}
+
+	/*
+	 * We are allowed to de-const the pointer based on our special knowledge;
+	 * it is const to the outside world.
+	 */
+	{
+		FLAC__EntropyCodingMethod_PartitionedRiceContents* best_partitioned_rice_contents = (FLAC__EntropyCodingMethod_PartitionedRiceContents*)best_partitioned_rice->contents;
+		FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(best_partitioned_rice_contents, max(6, best_partitioned_rice->order));
+		memcpy(best_partitioned_rice_contents->parameters, private_->partitioned_rice_contents_extra[best_parameters_index].parameters, sizeof(unsigned)*(1<<(best_partitioned_rice->order)));
+		memcpy(best_partitioned_rice_contents->raw_bits, private_->partitioned_rice_contents_extra[best_parameters_index].raw_bits, sizeof(unsigned)*(1<<(best_partitioned_rice->order)));
+	}
+
+	return best_residual_bits;
+}
+
+void precompute_partition_info_sums_(
+	const FLAC__uint32 abs_residual[],
+	FLAC__uint64 abs_residual_partition_sums[],
+	unsigned residual_samples,
+	unsigned predictor_order,
+	unsigned min_partition_order,
+	unsigned max_partition_order
+)
+{
+	int partition_order;
+	unsigned from_partition, to_partition = 0;
+	const unsigned blocksize = residual_samples + predictor_order;
+
+	/* first do max_partition_order */
+	for(partition_order = (int)max_partition_order; partition_order >= 0; partition_order--) {
+		FLAC__uint64 abs_residual_partition_sum;
+		FLAC__uint32 abs_r;
+		unsigned partition, partition_sample, partition_samples, residual_sample;
+		const unsigned partitions = 1u << partition_order;
+		const unsigned default_partition_samples = blocksize >> partition_order;
+
+		FLAC__ASSERT(default_partition_samples > predictor_order);
+
+		for(partition = residual_sample = 0; partition < partitions; partition++) {
+			partition_samples = default_partition_samples;
+			if(partition == 0)
+				partition_samples -= predictor_order;
+			abs_residual_partition_sum = 0;
+			for(partition_sample = 0; partition_sample < partition_samples; partition_sample++) {
+				abs_r = abs_residual[residual_sample];
+				abs_residual_partition_sum += abs_r;
+				residual_sample++;
+			}
+			abs_residual_partition_sums[partition] = abs_residual_partition_sum;
+		}
+		to_partition = partitions;
+		break;
+	}
+
+	/* now merge partitions for lower orders */
+	for(from_partition = 0, --partition_order; partition_order >= (int)min_partition_order; partition_order--) {
+		FLAC__uint64 s;
+		unsigned i;
+		const unsigned partitions = 1u << partition_order;
+		for(i = 0; i < partitions; i++) {
+			s = abs_residual_partition_sums[from_partition];
+			from_partition++;
+			abs_residual_partition_sums[to_partition] = s + abs_residual_partition_sums[from_partition];
+			from_partition++;
+			to_partition++;
+		}
+	}
+}
+
+void precompute_partition_info_escapes_(
+	const FLAC__int32 residual[],
+	unsigned raw_bits_per_partition[],
+	unsigned residual_samples,
+	unsigned predictor_order,
+	unsigned min_partition_order,
+	unsigned max_partition_order
+)
+{
+	int partition_order;
+	unsigned from_partition, to_partition = 0;
+	const unsigned blocksize = residual_samples + predictor_order;
+
+	/* first do max_partition_order */
+	for(partition_order = (int)max_partition_order; partition_order >= 0; partition_order--) {
+		FLAC__int32 r, residual_partition_min, residual_partition_max;
+		unsigned silog2_min, silog2_max;
+		unsigned partition, partition_sample, partition_samples, residual_sample;
+		const unsigned partitions = 1u << partition_order;
+		const unsigned default_partition_samples = blocksize >> partition_order;
+
+		FLAC__ASSERT(default_partition_samples > predictor_order);
+
+		for(partition = residual_sample = 0; partition < partitions; partition++) {
+			partition_samples = default_partition_samples;
+			if(partition == 0)
+				partition_samples -= predictor_order;
+			residual_partition_min = residual_partition_max = 0;
+			for(partition_sample = 0; partition_sample < partition_samples; partition_sample++) {
+				r = residual[residual_sample];
+				if(r < residual_partition_min)
+					residual_partition_min = r;
+				else if(r > residual_partition_max)
+					residual_partition_max = r;
+				residual_sample++;
+			}
+			silog2_min = FLAC__bitmath_silog2(residual_partition_min);
+			silog2_max = FLAC__bitmath_silog2(residual_partition_max);
+			raw_bits_per_partition[partition] = max(silog2_min, silog2_max);
+		}
+		to_partition = partitions;
+		break;
+	}
+
+	/* now merge partitions for lower orders */
+	for(from_partition = 0, --partition_order; partition_order >= (int)min_partition_order; partition_order--) {
+		unsigned m;
+		unsigned i;
+		const unsigned partitions = 1u << partition_order;
+		for(i = 0; i < partitions; i++) {
+			m = raw_bits_per_partition[from_partition];
+			from_partition++;
+			raw_bits_per_partition[to_partition] = max(m, raw_bits_per_partition[from_partition]);
+			from_partition++;
+			to_partition++;
+		}
+	}
+}
+
+#ifdef VARIABLE_RICE_BITS
+#undef VARIABLE_RICE_BITS
+#endif
+#ifndef DONT_ESTIMATE_RICE_BITS
+#define VARIABLE_RICE_BITS(value, parameter) ((value) >> (parameter))
+#endif
+
+#ifdef DONT_ESTIMATE_RICE_BITS
+FLAC__bool set_partitioned_rice_(
+	const FLAC__uint32 abs_residual[],
+	const FLAC__int32 residual[],
+	const unsigned residual_samples,
+	const unsigned predictor_order,
+	const unsigned suggested_rice_parameter,
+	const unsigned rice_parameter_search_dist,
+	const unsigned partition_order,
+	FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents,
+	unsigned *bits
+)
+#else
+FLAC__bool set_partitioned_rice_(
+	const FLAC__uint32 abs_residual[],
+	const unsigned residual_samples,
+	const unsigned predictor_order,
+	const unsigned suggested_rice_parameter,
+	const unsigned rice_parameter_search_dist,
+	const unsigned partition_order,
+	FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents,
+	unsigned *bits
+)
+#endif
+{
+	unsigned rice_parameter, partition_bits;
+#ifndef NO_RICE_SEARCH
+	unsigned best_partition_bits;
+	unsigned min_rice_parameter, max_rice_parameter, best_rice_parameter = 0;
+#endif
+	unsigned bits_ = FLAC__ENTROPY_CODING_METHOD_TYPE_LEN + FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN;
+	unsigned *parameters;
+
+	FLAC__ASSERT(suggested_rice_parameter < FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER);
+
+	FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(partitioned_rice_contents, max(6, partition_order));
+	parameters = partitioned_rice_contents->parameters;
+
+	if(partition_order == 0) {
+		unsigned i;
+
+#ifndef NO_RICE_SEARCH
+		if(rice_parameter_search_dist) {
+			if(suggested_rice_parameter < rice_parameter_search_dist)
+				min_rice_parameter = 0;
+			else
+				min_rice_parameter = suggested_rice_parameter - rice_parameter_search_dist;
+			max_rice_parameter = suggested_rice_parameter + rice_parameter_search_dist;
+			if(max_rice_parameter >= FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER) {
+#ifdef DEBUG_VERBOSE
+				fprintf(stderr, "clipping rice_parameter (%u -> %u) @2\n", max_rice_parameter, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1);
+#endif
+				max_rice_parameter = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1;
+			}
+		}
+		else
+			min_rice_parameter = max_rice_parameter = suggested_rice_parameter;
+
+		best_partition_bits = 0xffffffff;
+		for(rice_parameter = min_rice_parameter; rice_parameter <= max_rice_parameter; rice_parameter++) {
+#endif
+#ifdef VARIABLE_RICE_BITS
+#ifdef FLAC__SYMMETRIC_RICE
+			partition_bits = (2+rice_parameter) * residual_samples;
+#else
+			const unsigned rice_parameter_estimate = rice_parameter-1;
+			partition_bits = (1+rice_parameter) * residual_samples;
+#endif
+#else
+			partition_bits = 0;
+#endif
+			partition_bits += FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN;
+			for(i = 0; i < residual_samples; i++) {
+#ifdef VARIABLE_RICE_BITS
+#ifdef FLAC__SYMMETRIC_RICE
+				partition_bits += VARIABLE_RICE_BITS(abs_residual[i], rice_parameter);
+#else
+				partition_bits += VARIABLE_RICE_BITS(abs_residual[i], rice_parameter_estimate);
+#endif
+#else
+				partition_bits += FLAC__bitbuffer_rice_bits(residual[i], rice_parameter); /* NOTE: we will need to pass in residual[] in addition to abs_residual[] */
+#endif
+			}
+#ifndef NO_RICE_SEARCH
+			if(partition_bits < best_partition_bits) {
+				best_rice_parameter = rice_parameter;
+				best_partition_bits = partition_bits;
+			}
+		}
+#endif
+		parameters[0] = best_rice_parameter;
+		bits_ += best_partition_bits;
+	}
+	else {
+		unsigned partition, residual_sample, save_residual_sample, partition_sample;
+		unsigned partition_samples;
+		FLAC__uint64 mean, k;
+		const unsigned partitions = 1u << partition_order;
+		for(partition = residual_sample = 0; partition < partitions; partition++) {
+			partition_samples = (residual_samples+predictor_order) >> partition_order;
+			if(partition == 0) {
+				if(partition_samples <= predictor_order)
+					return false;
+				else
+					partition_samples -= predictor_order;
+			}
+			mean = 0;
+			save_residual_sample = residual_sample;
+			for(partition_sample = 0; partition_sample < partition_samples; residual_sample++, partition_sample++)
+				mean += abs_residual[residual_sample];
+			residual_sample = save_residual_sample;
+#ifdef FLAC__SYMMETRIC_RICE
+			mean += partition_samples >> 1; /* for rounding effect */
+			mean /= partition_samples;
+
+			/* calc rice_parameter = floor(log2(mean)) */
+			rice_parameter = 0;
+			mean>>=1;
+			while(mean) {
+				rice_parameter++;
+				mean >>= 1;
+			}
+#else
+			/* calc rice_parameter ala LOCO-I */
+			for(rice_parameter = 0, k = partition_samples; k < mean; rice_parameter++, k <<= 1)
+				;
+#endif
+			if(rice_parameter >= FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER) {
+#ifdef DEBUG_VERBOSE
+				fprintf(stderr, "clipping rice_parameter (%u -> %u) @3\n", rice_parameter, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1);
+#endif
+				rice_parameter = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1;
+			}
+
+#ifndef NO_RICE_SEARCH
+			if(rice_parameter_search_dist) {
+				if(rice_parameter < rice_parameter_search_dist)
+					min_rice_parameter = 0;
+				else
+					min_rice_parameter = rice_parameter - rice_parameter_search_dist;
+				max_rice_parameter = rice_parameter + rice_parameter_search_dist;
+				if(max_rice_parameter >= FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER) {
+#ifdef DEBUG_VERBOSE
+					fprintf(stderr, "clipping rice_parameter (%u -> %u) @4\n", max_rice_parameter, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1);
+#endif
+					max_rice_parameter = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1;
+				}
+			}
+			else
+				min_rice_parameter = max_rice_parameter = rice_parameter;
+
+			best_partition_bits = 0xffffffff;
+			for(rice_parameter = min_rice_parameter; rice_parameter <= max_rice_parameter; rice_parameter++) {
+#endif
+#ifdef VARIABLE_RICE_BITS
+#ifdef FLAC__SYMMETRIC_RICE
+				partition_bits = (2+rice_parameter) * partition_samples;
+#else
+				const unsigned rice_parameter_estimate = rice_parameter-1;
+				partition_bits = (1+rice_parameter) * partition_samples;
+#endif
+#else
+				partition_bits = 0;
+#endif
+				partition_bits += FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN;
+				save_residual_sample = residual_sample;
+				for(partition_sample = 0; partition_sample < partition_samples; residual_sample++, partition_sample++) {
+#ifdef VARIABLE_RICE_BITS
+#ifdef FLAC__SYMMETRIC_RICE
+					partition_bits += VARIABLE_RICE_BITS(abs_residual[residual_sample], rice_parameter);
+#else
+					partition_bits += VARIABLE_RICE_BITS(abs_residual[residual_sample], rice_parameter_estimate);
+#endif
+#else
+					partition_bits += FLAC__bitbuffer_rice_bits(residual[residual_sample], rice_parameter); /* NOTE: we will need to pass in residual[] in addition to abs_residual[] */
+#endif
+				}
+#ifndef NO_RICE_SEARCH
+				if(rice_parameter != max_rice_parameter)
+					residual_sample = save_residual_sample;
+				if(partition_bits < best_partition_bits) {
+					best_rice_parameter = rice_parameter;
+					best_partition_bits = partition_bits;
+				}
+			}
+#endif
+			parameters[partition] = best_rice_parameter;
+			bits_ += best_partition_bits;
+		}
+	}
+
+	*bits = bits_;
+	return true;
+}
+
+#ifdef DONT_ESTIMATE_RICE_BITS
+FLAC__bool set_partitioned_rice_with_precompute_(
+	const FLAC__int32 residual[],
+	const FLAC__uint64 abs_residual_partition_sums[],
+	const unsigned raw_bits_per_partition[],
+	const unsigned residual_samples,
+	const unsigned predictor_order,
+	const unsigned suggested_rice_parameter,
+	const unsigned rice_parameter_search_dist,
+	const unsigned partition_order,
+	const FLAC__bool search_for_escapes,
+	FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents,
+	unsigned *bits
+)
+#else
+FLAC__bool set_partitioned_rice_with_precompute_(
+	const FLAC__uint32 abs_residual[],
+	const FLAC__uint64 abs_residual_partition_sums[],
+	const unsigned raw_bits_per_partition[],
+	const unsigned residual_samples,
+	const unsigned predictor_order,
+	const unsigned suggested_rice_parameter,
+	const unsigned rice_parameter_search_dist,
+	const unsigned partition_order,
+	const FLAC__bool search_for_escapes,
+	FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents,
+	unsigned *bits
+)
+#endif
+{
+	unsigned rice_parameter, partition_bits;
+#ifndef NO_RICE_SEARCH
+	unsigned best_partition_bits;
+	unsigned min_rice_parameter, max_rice_parameter, best_rice_parameter = 0;
+#endif
+	unsigned flat_bits;
+	unsigned bits_ = FLAC__ENTROPY_CODING_METHOD_TYPE_LEN + FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN;
+	unsigned *parameters, *raw_bits;
+
+	FLAC__ASSERT(suggested_rice_parameter < FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER);
+
+	FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(partitioned_rice_contents, max(6, partition_order));
+	parameters = partitioned_rice_contents->parameters;
+	raw_bits = partitioned_rice_contents->raw_bits;
+
+	if(partition_order == 0) {
+		unsigned i;
+
+#ifndef NO_RICE_SEARCH
+		if(rice_parameter_search_dist) {
+			if(suggested_rice_parameter < rice_parameter_search_dist)
+				min_rice_parameter = 0;
+			else
+				min_rice_parameter = suggested_rice_parameter - rice_parameter_search_dist;
+			max_rice_parameter = suggested_rice_parameter + rice_parameter_search_dist;
+			if(max_rice_parameter >= FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER) {
+#ifdef DEBUG_VERBOSE
+				fprintf(stderr, "clipping rice_parameter (%u -> %u) @5\n", max_rice_parameter, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1);
+#endif
+				max_rice_parameter = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1;
+			}
+		}
+		else
+			min_rice_parameter = max_rice_parameter = suggested_rice_parameter;
+
+		best_partition_bits = 0xffffffff;
+		for(rice_parameter = min_rice_parameter; rice_parameter <= max_rice_parameter; rice_parameter++) {
+#endif
+#ifdef VARIABLE_RICE_BITS
+#ifdef FLAC__SYMMETRIC_RICE
+			partition_bits = (2+rice_parameter) * residual_samples;
+#else
+			const unsigned rice_parameter_estimate = rice_parameter-1;
+			partition_bits = (1+rice_parameter) * residual_samples;
+#endif
+#else
+			partition_bits = 0;
+#endif
+			partition_bits += FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN;
+			for(i = 0; i < residual_samples; i++) {
+#ifdef VARIABLE_RICE_BITS
+#ifdef FLAC__SYMMETRIC_RICE
+				partition_bits += VARIABLE_RICE_BITS(abs_residual[i], rice_parameter);
+#else
+				partition_bits += VARIABLE_RICE_BITS(abs_residual[i], rice_parameter_estimate);
+#endif
+#else
+				partition_bits += FLAC__bitbuffer_rice_bits(residual[i], rice_parameter); /* NOTE: we will need to pass in residual[] instead of abs_residual[] */
+#endif
+			}
+#ifndef NO_RICE_SEARCH
+			if(partition_bits < best_partition_bits) {
+				best_rice_parameter = rice_parameter;
+				best_partition_bits = partition_bits;
+			}
+		}
+#endif
+		if(search_for_escapes) {
+			flat_bits = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN + FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN + raw_bits_per_partition[0] * residual_samples;
+			if(flat_bits <= best_partition_bits) {
+				raw_bits[0] = raw_bits_per_partition[0];
+				best_rice_parameter = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER;
+				best_partition_bits = flat_bits;
+			}
+		}
+		parameters[0] = best_rice_parameter;
+		bits_ += best_partition_bits;
+	}
+	else {
+		unsigned partition, residual_sample, save_residual_sample, partition_sample;
+		unsigned partition_samples;
+		FLAC__uint64 mean, k;
+		const unsigned partitions = 1u << partition_order;
+		for(partition = residual_sample = 0; partition < partitions; partition++) {
+			partition_samples = (residual_samples+predictor_order) >> partition_order;
+			if(partition == 0) {
+				if(partition_samples <= predictor_order)
+					return false;
+				else
+					partition_samples -= predictor_order;
+			}
+			mean = abs_residual_partition_sums[partition];
+#ifdef FLAC__SYMMETRIC_RICE
+			mean += partition_samples >> 1; /* for rounding effect */
+			mean /= partition_samples;
+
+			/* calc rice_parameter = floor(log2(mean)) */
+			rice_parameter = 0;
+			mean>>=1;
+			while(mean) {
+				rice_parameter++;
+				mean >>= 1;
+			}
+#else
+			/* calc rice_parameter ala LOCO-I */
+			for(rice_parameter = 0, k = partition_samples; k < mean; rice_parameter++, k <<= 1)
+				;
+#endif
+			if(rice_parameter >= FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER) {
+#ifdef DEBUG_VERBOSE
+				fprintf(stderr, "clipping rice_parameter (%u -> %u) @6\n", rice_parameter, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1);
+#endif
+				rice_parameter = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1;
+			}
+
+#ifndef NO_RICE_SEARCH
+			if(rice_parameter_search_dist) {
+				if(rice_parameter < rice_parameter_search_dist)
+					min_rice_parameter = 0;
+				else
+					min_rice_parameter = rice_parameter - rice_parameter_search_dist;
+				max_rice_parameter = rice_parameter + rice_parameter_search_dist;
+				if(max_rice_parameter >= FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER) {
+#ifdef DEBUG_VERBOSE
+					fprintf(stderr, "clipping rice_parameter (%u -> %u) @7\n", max_rice_parameter, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1);
+#endif
+					max_rice_parameter = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1;
+				}
+			}
+			else
+				min_rice_parameter = max_rice_parameter = rice_parameter;
+
+			best_partition_bits = 0xffffffff;
+			for(rice_parameter = min_rice_parameter; rice_parameter <= max_rice_parameter; rice_parameter++) {
+#endif
+#ifdef VARIABLE_RICE_BITS
+#ifdef FLAC__SYMMETRIC_RICE
+				partition_bits = (2+rice_parameter) * partition_samples;
+#else
+				const unsigned rice_parameter_estimate = rice_parameter-1;
+				partition_bits = (1+rice_parameter) * partition_samples;
+#endif
+#else
+				partition_bits = 0;
+#endif
+				partition_bits += FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN;
+				save_residual_sample = residual_sample;
+				for(partition_sample = 0; partition_sample < partition_samples; residual_sample++, partition_sample++) {
+#ifdef VARIABLE_RICE_BITS
+#ifdef FLAC__SYMMETRIC_RICE
+					partition_bits += VARIABLE_RICE_BITS(abs_residual[residual_sample], rice_parameter);
+#else
+					partition_bits += VARIABLE_RICE_BITS(abs_residual[residual_sample], rice_parameter_estimate);
+#endif
+#else
+					partition_bits += FLAC__bitbuffer_rice_bits(residual[residual_sample], rice_parameter); /* NOTE: we will need to pass in residual[] instead of abs_residual[] */
+#endif
+				}
+#ifndef NO_RICE_SEARCH
+				if(rice_parameter != max_rice_parameter)
+					residual_sample = save_residual_sample;
+				if(partition_bits < best_partition_bits) {
+					best_rice_parameter = rice_parameter;
+					best_partition_bits = partition_bits;
+				}
+			}
+#endif
+			if(search_for_escapes) {
+				flat_bits = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN + FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN + raw_bits_per_partition[partition] * partition_samples;
+				if(flat_bits <= best_partition_bits) {
+					raw_bits[partition] = raw_bits_per_partition[partition];
+					best_rice_parameter = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER;
+					best_partition_bits = flat_bits;
+				}
+			}
+			parameters[partition] = best_rice_parameter;
+			bits_ += best_partition_bits;
+		}
+	}
+
+	*bits = bits_;
+	return true;
+}
+
+unsigned get_wasted_bits_(FLAC__int32 signal[], unsigned samples)
+{
+	unsigned i, shift;
+	FLAC__int32 x = 0;
+
+	for(i = 0; i < samples && !(x&1); i++)
+		x |= signal[i];
+
+	if(x == 0) {
+		shift = 0;
+	}
+	else {
+		for(shift = 0; !(x&1); shift++)
+			x >>= 1;
+	}
+
+	if(shift > 0) {
+		for(i = 0; i < samples; i++)
+			 signal[i] >>= shift;
+	}
+
+	return shift;
+}
+
+void append_to_verify_fifo_(verify_input_fifo *fifo, const FLAC__int32 * const input[], unsigned input_offset, unsigned channels, unsigned wide_samples)
+{
+	unsigned channel;
+
+	for(channel = 0; channel < channels; channel++)
+		memcpy(&fifo->data[channel][fifo->tail], &input[channel][input_offset], sizeof(FLAC__int32) * wide_samples);
+
+	fifo->tail += wide_samples;
+
+	FLAC__ASSERT(fifo->tail <= fifo->size);
+}
+
+void append_to_verify_fifo_interleaved_(verify_input_fifo *fifo, const FLAC__int32 input[], unsigned input_offset, unsigned channels, unsigned wide_samples)
+{
+	unsigned channel;
+	unsigned sample, wide_sample;
+	unsigned tail = fifo->tail;
+
+	sample = input_offset * channels;
+	for(wide_sample = 0; wide_sample < wide_samples; wide_sample++) {
+		for(channel = 0; channel < channels; channel++)
+			fifo->data[channel][tail] = input[sample++];
+		tail++;
+	}
+	fifo->tail = tail;
+
+	FLAC__ASSERT(fifo->tail <= fifo->size);
+}
+
+FLAC__StreamDecoderReadStatus verify_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data)
+{
+	FLAC__StreamEncoder *encoder = (FLAC__StreamEncoder*)client_data;
+	const unsigned encoded_bytes = encoder->private_->verify.output.bytes;
+	(void)decoder;
+
+	if(encoder->private_->verify.needs_magic_hack) {
+		FLAC__ASSERT(*bytes >= FLAC__STREAM_SYNC_LENGTH);
+		*bytes = FLAC__STREAM_SYNC_LENGTH;
+		memcpy(buffer, FLAC__STREAM_SYNC_STRING, *bytes);
+		encoder->private_->verify.needs_magic_hack = false;
+	}
+	else {
+		if(encoded_bytes == 0) {
+			/*
+			 * If we get here, a FIFO underflow has occurred,
+			 * which means there is a bug somewhere.
+			 */
+			FLAC__ASSERT(0);
+			return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+		}
+		else if(encoded_bytes < *bytes)
+			*bytes = encoded_bytes;
+		memcpy(buffer, encoder->private_->verify.output.data, *bytes);
+		encoder->private_->verify.output.data += *bytes;
+		encoder->private_->verify.output.bytes -= *bytes;
+	}
+
+	return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+}
+
+FLAC__StreamDecoderWriteStatus verify_write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
+{
+	FLAC__StreamEncoder *encoder = (FLAC__StreamEncoder *)client_data;
+	unsigned channel;
+	const unsigned channels = FLAC__stream_decoder_get_channels(decoder);
+	const unsigned blocksize = frame->header.blocksize;
+	const unsigned bytes_per_block = sizeof(FLAC__int32) * blocksize;
+
+	for(channel = 0; channel < channels; channel++) {
+		if(0 != memcmp(buffer[channel], encoder->private_->verify.input_fifo.data[channel], bytes_per_block)) {
+			unsigned i, sample = 0;
+			FLAC__int32 expect = 0, got = 0;
+
+			for(i = 0; i < blocksize; i++) {
+				if(buffer[channel][i] != encoder->private_->verify.input_fifo.data[channel][i]) {
+					sample = i;
+					expect = (FLAC__int32)encoder->private_->verify.input_fifo.data[channel][i];
+					got = (FLAC__int32)buffer[channel][i];
+					break;
+				}
+			}
+			FLAC__ASSERT(i < blocksize);
+			FLAC__ASSERT(frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER);
+			encoder->private_->verify.error_stats.absolute_sample = frame->header.number.sample_number + sample;
+			encoder->private_->verify.error_stats.frame_number = (unsigned)(frame->header.number.sample_number / blocksize);
+			encoder->private_->verify.error_stats.channel = channel;
+			encoder->private_->verify.error_stats.sample = sample;
+			encoder->private_->verify.error_stats.expected = expect;
+			encoder->private_->verify.error_stats.got = got;
+			encoder->protected_->state = FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA;
+			return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+		}
+	}
+	/* dequeue the frame from the fifo */
+	for(channel = 0; channel < channels; channel++) {
+		memmove(&encoder->private_->verify.input_fifo.data[channel][0], &encoder->private_->verify.input_fifo.data[channel][blocksize], encoder->private_->verify.input_fifo.tail - blocksize);
+	}
+	encoder->private_->verify.input_fifo.tail -= blocksize;
+	return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+
+void verify_metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
+{
+	(void)decoder, (void)metadata, (void)client_data;
+}
+
+void verify_error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+	FLAC__StreamEncoder *encoder = (FLAC__StreamEncoder*)client_data;
+	(void)decoder, (void)status;
+	encoder->protected_->state = FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR;
+}
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/stream_encoder_framing.c
@@ -1,0 +1,499 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004  Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <string.h> /* for strlen() */
+#include "private/stream_encoder_framing.h"
+#include "private/crc.h"
+#include "FLAC/assert.h"
+
+#ifdef max
+#undef max
+#endif
+#define max(x,y) ((x)>(y)?(x):(y))
+
+static FLAC__bool add_entropy_coding_method_(FLAC__BitBuffer *bb, const FLAC__EntropyCodingMethod *method);
+static FLAC__bool add_residual_partitioned_rice_(FLAC__BitBuffer *bb, const FLAC__int32 residual[], const unsigned residual_samples, const unsigned predictor_order, const unsigned rice_parameters[], const unsigned raw_bits[], const unsigned partition_order);
+
+FLAC__bool FLAC__add_metadata_block(const FLAC__StreamMetadata *metadata, FLAC__BitBuffer *bb)
+{
+	unsigned i, j;
+	const unsigned vendor_string_length = (unsigned)strlen(FLAC__VENDOR_STRING);
+
+	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;
+
+	/*
+	 * First, for VORBIS_COMMENTs, adjust the length to reflect our vendor string
+	 */
+	i = metadata->length;
+	if(metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
+		FLAC__ASSERT(metadata->data.vorbis_comment.vendor_string.length == 0 || 0 != metadata->data.vorbis_comment.vendor_string.entry);
+		i -= metadata->data.vorbis_comment.vendor_string.length;
+		i += vendor_string_length;
+	}
+	FLAC__ASSERT(i < (1u << FLAC__STREAM_METADATA_LENGTH_LEN));
+	if(!FLAC__bitbuffer_write_raw_uint32(bb, i, FLAC__STREAM_METADATA_LENGTH_LEN))
+		return false;
+
+	switch(metadata->type) {
+		case FLAC__METADATA_TYPE_STREAMINFO:
+			FLAC__ASSERT(metadata->data.stream_info.min_blocksize < (1u << FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN));
+			if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->data.stream_info.min_blocksize, FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN))
+				return false;
+			FLAC__ASSERT(metadata->data.stream_info.max_blocksize < (1u << FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN));
+			if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->data.stream_info.max_blocksize, FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN))
+				return false;
+			FLAC__ASSERT(metadata->data.stream_info.min_framesize < (1u << FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN));
+			if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->data.stream_info.min_framesize, FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN))
+				return false;
+			FLAC__ASSERT(metadata->data.stream_info.max_framesize < (1u << FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN));
+			if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->data.stream_info.max_framesize, FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN))
+				return false;
+			FLAC__ASSERT(FLAC__format_sample_rate_is_valid(metadata->data.stream_info.sample_rate));
+			if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->data.stream_info.sample_rate, FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN))
+				return false;
+			FLAC__ASSERT(metadata->data.stream_info.channels > 0);
+			FLAC__ASSERT(metadata->data.stream_info.channels <= (1u << FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN));
+			if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->data.stream_info.channels-1, FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN))
+				return false;
+			FLAC__ASSERT(metadata->data.stream_info.bits_per_sample > 0);
+			FLAC__ASSERT(metadata->data.stream_info.bits_per_sample <= (1u << FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN));
+			if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->data.stream_info.bits_per_sample-1, FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN))
+				return false;
+			if(!FLAC__bitbuffer_write_raw_uint64(bb, metadata->data.stream_info.total_samples, FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN))
+				return false;
+			if(!FLAC__bitbuffer_write_byte_block(bb, metadata->data.stream_info.md5sum, 16))
+				return false;
+			break;
+		case FLAC__METADATA_TYPE_PADDING:
+			if(!FLAC__bitbuffer_write_zeroes(bb, metadata->length * 8))
+				return false;
+			break;
+		case FLAC__METADATA_TYPE_APPLICATION:
+			if(!FLAC__bitbuffer_write_byte_block(bb, metadata->data.application.id, FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8))
+				return false;
+			if(!FLAC__bitbuffer_write_byte_block(bb, metadata->data.application.data, metadata->length - (FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8)))
+				return false;
+			break;
+		case FLAC__METADATA_TYPE_SEEKTABLE:
+			for(i = 0; i < metadata->data.seek_table.num_points; i++) {
+				if(!FLAC__bitbuffer_write_raw_uint64(bb, metadata->data.seek_table.points[i].sample_number, FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN))
+					return false;
+				if(!FLAC__bitbuffer_write_raw_uint64(bb, metadata->data.seek_table.points[i].stream_offset, FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN))
+					return false;
+				if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->data.seek_table.points[i].frame_samples, FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN))
+					return false;
+			}
+			break;
+		case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+			if(!FLAC__bitbuffer_write_raw_uint32_little_endian(bb, vendor_string_length))
+				return false;
+			if(!FLAC__bitbuffer_write_byte_block(bb, (const FLAC__byte*)FLAC__VENDOR_STRING, vendor_string_length))
+				return false;
+			if(!FLAC__bitbuffer_write_raw_uint32_little_endian(bb, metadata->data.vorbis_comment.num_comments))
+				return false;
+			for(i = 0; i < metadata->data.vorbis_comment.num_comments; i++) {
+				if(!FLAC__bitbuffer_write_raw_uint32_little_endian(bb, metadata->data.vorbis_comment.comments[i].length))
+					return false;
+				if(!FLAC__bitbuffer_write_byte_block(bb, metadata->data.vorbis_comment.comments[i].entry, metadata->data.vorbis_comment.comments[i].length))
+					return false;
+			}
+			break;
+		case FLAC__METADATA_TYPE_CUESHEET:
+			FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN % 8 == 0);
+			if(!FLAC__bitbuffer_write_byte_block(bb, (const FLAC__byte*)metadata->data.cue_sheet.media_catalog_number, FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN/8))
+				return false;
+			if(!FLAC__bitbuffer_write_raw_uint64(bb, metadata->data.cue_sheet.lead_in, FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN))
+				return false;
+			if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->data.cue_sheet.is_cd? 1 : 0, FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN))
+				return false;
+			if(!FLAC__bitbuffer_write_zeroes(bb, FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN))
+				return false;
+			if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->data.cue_sheet.num_tracks, FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN))
+				return false;
+			for(i = 0; i < metadata->data.cue_sheet.num_tracks; i++) {
+				const FLAC__StreamMetadata_CueSheet_Track *track = metadata->data.cue_sheet.tracks + i;
+
+				if(!FLAC__bitbuffer_write_raw_uint64(bb, track->offset, FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN))
+					return false;
+				if(!FLAC__bitbuffer_write_raw_uint32(bb, track->number, FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN))
+					return false;
+				FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN % 8 == 0);
+				if(!FLAC__bitbuffer_write_byte_block(bb, (const FLAC__byte*)track->isrc, FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN/8))
+					return false;
+				if(!FLAC__bitbuffer_write_raw_uint32(bb, track->type, FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN))
+					return false;
+				if(!FLAC__bitbuffer_write_raw_uint32(bb, track->pre_emphasis, FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN))
+					return false;
+				if(!FLAC__bitbuffer_write_zeroes(bb, FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN))
+					return false;
+				if(!FLAC__bitbuffer_write_raw_uint32(bb, track->num_indices, FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN))
+					return false;
+				for(j = 0; j < track->num_indices; j++) {
+					const FLAC__StreamMetadata_CueSheet_Index *index = track->indices + j;
+
+					if(!FLAC__bitbuffer_write_raw_uint64(bb, index->offset, FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN))
+						return false;
+					if(!FLAC__bitbuffer_write_raw_uint32(bb, index->number, FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN))
+						return false;
+					if(!FLAC__bitbuffer_write_zeroes(bb, FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN))
+						return false;
+				}
+			}
+			break;
+		default:
+			if(!FLAC__bitbuffer_write_byte_block(bb, metadata->data.unknown.data, metadata->length))
+				return false;
+			break;
+	}
+
+	FLAC__ASSERT(FLAC__bitbuffer_is_byte_aligned(bb));
+	return true;
+}
+
+FLAC__bool FLAC__frame_add_header(const FLAC__FrameHeader *header, FLAC__bool streamable_subset, FLAC__BitBuffer *bb)
+{
+	unsigned u, blocksize_hint, sample_rate_hint;
+
+	FLAC__ASSERT(FLAC__bitbuffer_is_byte_aligned(bb));
+
+	if(!FLAC__bitbuffer_write_raw_uint32(bb, FLAC__FRAME_HEADER_SYNC, FLAC__FRAME_HEADER_SYNC_LEN))
+		return false;
+
+	if(!FLAC__bitbuffer_write_raw_uint32(bb, 0, FLAC__FRAME_HEADER_RESERVED_LEN))
+		return false;
+
+	FLAC__ASSERT(header->blocksize > 0 && header->blocksize <= FLAC__MAX_BLOCK_SIZE);
+	/* when this assertion holds true, any legal blocksize can be expressed in the frame header */
+	FLAC__ASSERT(FLAC__MAX_BLOCK_SIZE <= 65535u);
+	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;
+		case   256: u = 8; break;
+		case   512: u = 9; break;
+		case  1024: u = 10; break;
+		case  2048: u = 11; break;
+		case  4096: u = 12; break;
+		case  8192: u = 13; break;
+		case 16384: u = 14; break;
+		case 32768: u = 15; break;
+		default:
+			if(header->blocksize <= 0x100)
+				blocksize_hint = u = 6;
+			else if(header->blocksize <= 0x10000)
+				blocksize_hint = u = 7;
+			else {
+				FLAC__ASSERT(0);
+				return false;
+			}
+			break;
+	}
+	if(!FLAC__bitbuffer_write_raw_uint32(bb, u, FLAC__FRAME_HEADER_BLOCK_SIZE_LEN))
+		return false;
+
+	FLAC__ASSERT(FLAC__format_sample_rate_is_valid(header->sample_rate));
+	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(header->sample_rate <= 255000 && header->sample_rate % 1000 == 0)
+				sample_rate_hint = u = 12;
+			else if(header->sample_rate % 10 == 0)
+				sample_rate_hint = u = 14;
+			else if(header->sample_rate <= 0xffff)
+				sample_rate_hint = u = 13;
+			else if(streamable_subset) {
+				FLAC__ASSERT(0);
+				return false;
+			}
+			else
+				u = 0;
+			break;
+	}
+	if(!FLAC__bitbuffer_write_raw_uint32(bb, u, FLAC__FRAME_HEADER_SAMPLE_RATE_LEN))
+		return false;
+
+	FLAC__ASSERT(header->channels > 0 && header->channels <= (1u << FLAC__STREAM_METADATA_STREAMINFO_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:
+			FLAC__ASSERT(header->channels == 2);
+			u = 8;
+			break;
+		case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE:
+			FLAC__ASSERT(header->channels == 2);
+			u = 9;
+			break;
+		case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE:
+			FLAC__ASSERT(header->channels == 2);
+			u = 10;
+			break;
+		default:
+			FLAC__ASSERT(0);
+	}
+	if(!FLAC__bitbuffer_write_raw_uint32(bb, u, FLAC__FRAME_HEADER_CHANNEL_ASSIGNMENT_LEN))
+		return false;
+
+	FLAC__ASSERT(header->bits_per_sample > 0 && header->bits_per_sample <= (1u << FLAC__STREAM_METADATA_STREAMINFO_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;
+
+	FLAC__ASSERT(header->number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER);
+	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 */
+	if(!FLAC__bitbuffer_write_raw_uint32(bb, FLAC__bitbuffer_get_write_crc8(bb), FLAC__FRAME_HEADER_CRC_LEN))
+		return false;
+
+	return true;
+}
+
+FLAC__bool FLAC__subframe_add_constant(const FLAC__Subframe_Constant *subframe, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitBuffer *bb)
+{
+	FLAC__bool ok;
+
+	ok =
+		FLAC__bitbuffer_write_raw_uint32(bb, FLAC__SUBFRAME_TYPE_CONSTANT_BYTE_ALIGNED_MASK | (wasted_bits? 1:0), FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN) &&
+		(wasted_bits? FLAC__bitbuffer_write_unary_unsigned(bb, wasted_bits-1) : true) &&
+		FLAC__bitbuffer_write_raw_int32(bb, subframe->value, subframe_bps)
+	;
+
+	return ok;
+}
+
+FLAC__bool FLAC__subframe_add_fixed(const FLAC__Subframe_Fixed *subframe, unsigned residual_samples, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitBuffer *bb)
+{
+	unsigned i;
+
+	if(!FLAC__bitbuffer_write_raw_uint32(bb, FLAC__SUBFRAME_TYPE_FIXED_BYTE_ALIGNED_MASK | (subframe->order<<1) | (wasted_bits? 1:0), FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN))
+		return false;
+	if(wasted_bits)
+		if(!FLAC__bitbuffer_write_unary_unsigned(bb, wasted_bits-1))
+			return false;
+
+	for(i = 0; i < subframe->order; i++)
+		if(!FLAC__bitbuffer_write_raw_int32(bb, subframe->warmup[i], subframe_bps))
+			return false;
+
+	if(!add_entropy_coding_method_(bb, &subframe->entropy_coding_method))
+		return false;
+	switch(subframe->entropy_coding_method.type) {
+		case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE:
+			if(!add_residual_partitioned_rice_(bb, subframe->residual, residual_samples, subframe->order, subframe->entropy_coding_method.data.partitioned_rice.contents->parameters, subframe->entropy_coding_method.data.partitioned_rice.contents->raw_bits, subframe->entropy_coding_method.data.partitioned_rice.order))
+				return false;
+			break;
+		default:
+			FLAC__ASSERT(0);
+	}
+
+	return true;
+}
+
+FLAC__bool FLAC__subframe_add_lpc(const FLAC__Subframe_LPC *subframe, unsigned residual_samples, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitBuffer *bb)
+{
+	unsigned i;
+
+	if(!FLAC__bitbuffer_write_raw_uint32(bb, FLAC__SUBFRAME_TYPE_LPC_BYTE_ALIGNED_MASK | ((subframe->order-1)<<1) | (wasted_bits? 1:0), FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN))
+		return false;
+	if(wasted_bits)
+		if(!FLAC__bitbuffer_write_unary_unsigned(bb, wasted_bits-1))
+			return false;
+
+	for(i = 0; i < subframe->order; i++)
+		if(!FLAC__bitbuffer_write_raw_int32(bb, subframe->warmup[i], subframe_bps))
+			return false;
+
+	if(!FLAC__bitbuffer_write_raw_uint32(bb, subframe->qlp_coeff_precision-1, FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN))
+		return false;
+	if(!FLAC__bitbuffer_write_raw_int32(bb, subframe->quantization_level, FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN))
+		return false;
+	for(i = 0; i < subframe->order; i++)
+		if(!FLAC__bitbuffer_write_raw_int32(bb, subframe->qlp_coeff[i], subframe->qlp_coeff_precision))
+			return false;
+
+	if(!add_entropy_coding_method_(bb, &subframe->entropy_coding_method))
+		return false;
+	switch(subframe->entropy_coding_method.type) {
+		case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE:
+			if(!add_residual_partitioned_rice_(bb, subframe->residual, residual_samples, subframe->order, subframe->entropy_coding_method.data.partitioned_rice.contents->parameters, subframe->entropy_coding_method.data.partitioned_rice.contents->raw_bits, subframe->entropy_coding_method.data.partitioned_rice.order))
+				return false;
+			break;
+		default:
+			FLAC__ASSERT(0);
+	}
+
+	return true;
+}
+
+FLAC__bool FLAC__subframe_add_verbatim(const FLAC__Subframe_Verbatim *subframe, unsigned samples, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitBuffer *bb)
+{
+	unsigned i;
+	const FLAC__int32 *signal = subframe->data;
+
+	if(!FLAC__bitbuffer_write_raw_uint32(bb, FLAC__SUBFRAME_TYPE_VERBATIM_BYTE_ALIGNED_MASK | (wasted_bits? 1:0), FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN))
+		return false;
+	if(wasted_bits)
+		if(!FLAC__bitbuffer_write_unary_unsigned(bb, wasted_bits-1))
+			return false;
+
+	for(i = 0; i < samples; i++)
+		if(!FLAC__bitbuffer_write_raw_int32(bb, signal[i], subframe_bps))
+			return false;
+
+	return true;
+}
+
+FLAC__bool 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:
+			FLAC__ASSERT(0);
+	}
+	return true;
+}
+
+FLAC__bool add_residual_partitioned_rice_(FLAC__BitBuffer *bb, const FLAC__int32 residual[], const unsigned residual_samples, const unsigned predictor_order, const unsigned rice_parameters[], const unsigned raw_bits[], 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;
+		if(rice_parameters[0] < FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER) {
+			for(i = 0; i < residual_samples; i++) {
+#ifdef FLAC__SYMMETRIC_RICE
+				if(!FLAC__bitbuffer_write_symmetric_rice_signed(bb, residual[i], rice_parameters[0]))
+					return false;
+#else
+				if(!FLAC__bitbuffer_write_rice_signed(bb, residual[i], rice_parameters[0]))
+					return false;
+#endif
+			}
+		}
+		else {
+			if(!FLAC__bitbuffer_write_raw_uint32(bb, raw_bits[0], FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN))
+				return false;
+			for(i = 0; i < residual_samples; i++) {
+				if(!FLAC__bitbuffer_write_raw_int32(bb, residual[i], raw_bits[0]))
+					return false;
+			}
+		}
+		return true;
+	}
+	else {
+		unsigned i, j, k = 0, k_last = 0;
+		unsigned partition_samples;
+		const unsigned default_partition_samples = (residual_samples+predictor_order) >> partition_order;
+		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 = default_partition_samples;
+			if(i == 0)
+				partition_samples -= predictor_order;
+			k += partition_samples;
+			if(rice_parameters[i] < FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER) {
+				for(j = k_last; j < k; j++) {
+#ifdef FLAC__SYMMETRIC_RICE
+					if(!FLAC__bitbuffer_write_symmetric_rice_signed(bb, residual[j], rice_parameters[i]))
+						return false;
+#else
+					if(!FLAC__bitbuffer_write_rice_signed(bb, residual[j], rice_parameters[i]))
+						return false;
+#endif
+				}
+			}
+			else {
+				if(!FLAC__bitbuffer_write_raw_uint32(bb, raw_bits[i], FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN))
+					return false;
+				for(j = k_last; j < k; j++) {
+					if(!FLAC__bitbuffer_write_raw_int32(bb, residual[j], raw_bits[i]))
+						return false;
+				}
+			}
+			k_last = k;
+		}
+		return true;
+	}
+}
--- a/sys/src/cmd/audio/mkfile
+++ b/sys/src/cmd/audio/mkfile
@@ -1,7 +1,7 @@
 </$objtype/mkfile
 
-LIBS=libogg libvorbis
-PROGS=oggdec oggenc mp3dec mp3enc 
+LIBS=libogg libvorbis libFLAC
+PROGS=oggdec oggenc mp3dec mp3enc flacdec
 #libs must be made first
 DIRS=$LIBS $PROGS
 
--- a/sys/src/cmd/file.c
+++ b/sys/src/cmd/file.c
@@ -588,7 +588,7 @@
 	/* "pXc2 */
 	0x32630070,	0xFFFF00FF,	"pac4 audio file\n",	OCTET,
 	0xBA010000,	0xFFFFFFFF,	"mpeg system stream\n",	OCTET,
-	0x43614c66,	0xFFFFFFFF,	"FLAC audio file\n",	OCTET,
+	0x43614c66,	0xFFFFFFFF,	"FLAC audio file\n",	"audio/flac",
 	0x30800CC0,	0xFFFFFFFF,	"inferno .dis executable\n", OCTET,
 	0x04034B50,	0xFFFFFFFF,	"zip archive\n", "application/zip",
 	070707,		0xFFFF,		"cpio archive\n", "application/x-cpio",