shithub: riscv

Download patch

ref: 2d2ffac86f788ac6bed73d873f837bbd9849a2e4
parent: 897da507f4efdf67afb3b589cb9240fe217545af
author: ftrvxmtrx <[email protected]>
date: Sat Mar 5 05:32:47 EST 2016

libFLAC: update to 1.3.1

--- a/sys/src/cmd/audio/flacdec/flacdec.c
+++ b/sys/src/cmd/audio/flacdec/flacdec.c
@@ -8,18 +8,18 @@
 static int sts;
 
 static FLAC__StreamDecoderReadStatus
-decinput(FLAC__StreamDecoder *dec, FLAC__byte buffer[], unsigned *bytes, void *client_data)
+decinput(FLAC__StreamDecoder *dec, FLAC__byte buffer[], size_t *bytes, void *client_data)
 {
 	int n = *bytes;
 
-	n = fread(buffer,1,n,stdin);
-	if(n <= 0){
-		*bytes = 0;
+	n = fread(buffer, 1, n, stdin);
+	if(n < 0)
+		return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+	if(n == 0)
 		return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
-	} else {
-		*bytes = n;
-		return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
-	}
+
+	*bytes = n;
+	return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
 }
 
 static FLAC__StreamDecoderWriteStatus
@@ -111,11 +111,6 @@
 {
 }
 
-static void
-decmeta(FLAC__StreamDecoder *dec, FLAC__StreamMetadata *metadata, void *client_data)
-{
-}
-
 int main(int argc, char *argv[])
 {
 	FLAC__bool ok = true;
@@ -122,11 +117,7 @@
 	FLAC__StreamDecoder *dec = 0;
 
 	dec = FLAC__stream_decoder_new();
-	FLAC__stream_decoder_set_read_callback(dec, decinput);
-	FLAC__stream_decoder_set_write_callback(dec, decoutput);
-	FLAC__stream_decoder_set_error_callback(dec, decerror);
-	FLAC__stream_decoder_set_metadata_callback(dec, decmeta);
-	FLAC__stream_decoder_init(dec);
+	FLAC__stream_decoder_init_stream(dec, decinput, NULL, NULL, NULL, NULL, decoutput, NULL, decerror, NULL);
 	FLAC__stream_decoder_process_until_end_of_stream(dec);
 	FLAC__stream_decoder_finish(dec);
 
--- a/sys/src/cmd/audio/libFLAC/FLAC/all.h
+++ b/sys/src/cmd/audio/libFLAC/FLAC/all.h
@@ -1,5 +1,6 @@
 /* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2000,2001,2002,2003,2004  Josh Coalson
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2014  Xiph.Org Foundation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -36,13 +37,9 @@
 
 #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"
 
@@ -63,7 +60,7 @@
  * 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/...
+ * in your include area (for example /usr/include/FLAC/...).
  *
  * By writing a little code and linking against libFLAC, it is
  * relatively easy to add FLAC support to another program.  The
@@ -84,11 +81,9 @@
  * 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>.
+ * libFLAC also supports encoding to and decoding from Ogg FLAC.
+ * However the metadata editing interfaces currently have limited
+ * read-only support for Ogg FLAC files.
  *
  * \section cpp_api FLAC C++ API
  *
@@ -98,14 +93,10 @@
  * 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++/...
+ * for the C++ API will be installed in your include area (for
+ * example /usr/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
+ * libFLAC++ is also licensed under
  * <A HREF="../license.html">Xiph's BSD license</A>.
  *
  * \section getting_started Getting Started
@@ -121,6 +112,15 @@
  * individual functions.  You can see different views of the individual
  * functions through the links in top bar across this page.
  *
+ * If you prefer a more hands-on approach, you can jump right to some
+ * <A HREF="../documentation_example_code.html">example code</A>.
+ *
+ * \section porting_guide Porting Guide
+ *
+ * Starting with FLAC 1.1.3 a \link porting Porting Guide \endlink
+ * has been introduced which gives detailed instructions on how to
+ * port your code to newer versions of FLAC.
+ *
  * \section embedded_developers Embedded Developers
  *
  * libFLAC has grown larger over time as more functionality has been
@@ -132,16 +132,229 @@
  * 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
+ * - The decoders and encoders depend on the bitbuffer.
+ * - The decoder is independent of the encoder.  The encoder uses the
+ *   decoder because of the verify feature, but this can be removed if
+ *   not needed.
+ * - Parts of the metadata interface require the stream decoder (but not
+ *   the encoder).
+ * - Ogg support is selectable through the compile time macro
+ *   \c FLAC__HAS_OGG.
  *
  * 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.
+ * encoder, and no metadata interface, you can remove the stream encoder
+ * and the metadata interface, which will greatly reduce the size of the
+ * library.
+ *
+ * Also, there are several places in the libFLAC code with comments marked
+ * with "OPT:" where a #define can be changed to enable code that might be
+ * faster on a specific platform.  Experimenting with these can yield faster
+ * binaries.
+ */
+
+/** \defgroup porting Porting Guide for New Versions
+ *
+ * This module describes differences in the library interfaces from
+ * version to version.  It assists in the porting of code that uses
+ * the libraries to newer versions of FLAC.
+ *
+ * One simple facility for making porting easier that has been added
+ * in FLAC 1.1.3 is a set of \c #defines in \c export.h of each
+ * library's includes (e.g. \c include/FLAC/export.h).  The
+ * \c #defines mirror the libraries'
+ * <A HREF="http://www.gnu.org/software/libtool/manual/libtool.html#Libtool-versioning">libtool version numbers</A>,
+ * e.g. in libFLAC there are \c FLAC_API_VERSION_CURRENT,
+ * \c FLAC_API_VERSION_REVISION, and \c FLAC_API_VERSION_AGE.
+ * These can be used to support multiple versions of an API during the
+ * transition phase, e.g.
+ *
+ * \code
+ * #if !defined(FLAC_API_VERSION_CURRENT) || FLAC_API_VERSION_CURRENT <= 7
+ *   legacy code
+ * #else
+ *   new code
+ * #endif
+ * \endcode
+ *
+ * The the source will work for multiple versions and the legacy code can
+ * easily be removed when the transition is complete.
+ *
+ * Another available symbol is FLAC_API_SUPPORTS_OGG_FLAC (defined in
+ * include/FLAC/export.h), which can be used to determine whether or not
+ * the library has been compiled with support for Ogg FLAC.  This is
+ * simpler than trying to call an Ogg init function and catching the
+ * error.
+ */
+
+/** \defgroup porting_1_1_2_to_1_1_3 Porting from FLAC 1.1.2 to 1.1.3
+ *  \ingroup porting
+ *
+ *  \brief
+ *  This module describes porting from FLAC 1.1.2 to FLAC 1.1.3.
+ *
+ * The main change between the APIs in 1.1.2 and 1.1.3 is that they have
+ * been simplified.  First, libOggFLAC has been merged into libFLAC and
+ * libOggFLAC++ has been merged into libFLAC++.  Second, both the three
+ * decoding layers and three encoding layers have been merged into a
+ * single stream decoder and stream encoder.  That is, the functionality
+ * of FLAC__SeekableStreamDecoder and FLAC__FileDecoder has been merged
+ * into FLAC__StreamDecoder, and FLAC__SeekableStreamEncoder and
+ * FLAC__FileEncoder into FLAC__StreamEncoder.  Only the
+ * FLAC__StreamDecoder and FLAC__StreamEncoder remain.  What this means
+ * is there is now a single API that can be used to encode or decode
+ * streams to/from native FLAC or Ogg FLAC and the single API can work
+ * on both seekable and non-seekable streams.
+ *
+ * Instead of creating an encoder or decoder of a certain layer, now the
+ * client will always create a FLAC__StreamEncoder or
+ * FLAC__StreamDecoder.  The old layers are now differentiated by the
+ * initialization function.  For example, for the decoder,
+ * FLAC__stream_decoder_init() has been replaced by
+ * FLAC__stream_decoder_init_stream().  This init function takes
+ * callbacks for the I/O, and the seeking callbacks are optional.  This
+ * allows the client to use the same object for seekable and
+ * non-seekable streams.  For decoding a FLAC file directly, the client
+ * can use FLAC__stream_decoder_init_file() and pass just a filename
+ * and fewer callbacks; most of the other callbacks are supplied
+ * internally.  For situations where fopen()ing by filename is not
+ * possible (e.g. Unicode filenames on Windows) the client can instead
+ * open the file itself and supply the FILE* to
+ * FLAC__stream_decoder_init_FILE().  The init functions now returns a
+ * FLAC__StreamDecoderInitStatus instead of FLAC__StreamDecoderState.
+ * Since the callbacks and client data are now passed to the init
+ * function, the FLAC__stream_decoder_set_*_callback() functions and
+ * FLAC__stream_decoder_set_client_data() are no longer needed.  The
+ * rest of the calls to the decoder are the same as before.
+ *
+ * There are counterpart init functions for Ogg FLAC, e.g.
+ * FLAC__stream_decoder_init_ogg_stream().  All the rest of the calls
+ * and callbacks are the same as for native FLAC.
+ *
+ * As an example, in FLAC 1.1.2 a seekable stream decoder would have
+ * been set up like so:
+ *
+ * \code
+ * FLAC__SeekableStreamDecoder *decoder = FLAC__seekable_stream_decoder_new();
+ * if(decoder == NULL) do_something;
+ * FLAC__seekable_stream_decoder_set_md5_checking(decoder, true);
+ * [... other settings ...]
+ * FLAC__seekable_stream_decoder_set_read_callback(decoder, my_read_callback);
+ * FLAC__seekable_stream_decoder_set_seek_callback(decoder, my_seek_callback);
+ * FLAC__seekable_stream_decoder_set_tell_callback(decoder, my_tell_callback);
+ * FLAC__seekable_stream_decoder_set_length_callback(decoder, my_length_callback);
+ * FLAC__seekable_stream_decoder_set_eof_callback(decoder, my_eof_callback);
+ * FLAC__seekable_stream_decoder_set_write_callback(decoder, my_write_callback);
+ * FLAC__seekable_stream_decoder_set_metadata_callback(decoder, my_metadata_callback);
+ * FLAC__seekable_stream_decoder_set_error_callback(decoder, my_error_callback);
+ * FLAC__seekable_stream_decoder_set_client_data(decoder, my_client_data);
+ * if(FLAC__seekable_stream_decoder_init(decoder) != FLAC__SEEKABLE_STREAM_DECODER_OK) do_something;
+ * \endcode
+ *
+ * In FLAC 1.1.3 it is like this:
+ *
+ * \code
+ * FLAC__StreamDecoder *decoder = FLAC__stream_decoder_new();
+ * if(decoder == NULL) do_something;
+ * FLAC__stream_decoder_set_md5_checking(decoder, true);
+ * [... other settings ...]
+ * if(FLAC__stream_decoder_init_stream(
+ *   decoder,
+ *   my_read_callback,
+ *   my_seek_callback,      // or NULL
+ *   my_tell_callback,      // or NULL
+ *   my_length_callback,    // or NULL
+ *   my_eof_callback,       // or NULL
+ *   my_write_callback,
+ *   my_metadata_callback,  // or NULL
+ *   my_error_callback,
+ *   my_client_data
+ * ) != FLAC__STREAM_DECODER_INIT_STATUS_OK) do_something;
+ * \endcode
+ *
+ * or you could do;
+ *
+ * \code
+ * [...]
+ * FILE *file = fopen("somefile.flac","rb");
+ * if(file == NULL) do_somthing;
+ * if(FLAC__stream_decoder_init_FILE(
+ *   decoder,
+ *   file,
+ *   my_write_callback,
+ *   my_metadata_callback,  // or NULL
+ *   my_error_callback,
+ *   my_client_data
+ * ) != FLAC__STREAM_DECODER_INIT_STATUS_OK) do_something;
+ * \endcode
+ *
+ * or just:
+ *
+ * \code
+ * [...]
+ * if(FLAC__stream_decoder_init_file(
+ *   decoder,
+ *   "somefile.flac",
+ *   my_write_callback,
+ *   my_metadata_callback,  // or NULL
+ *   my_error_callback,
+ *   my_client_data
+ * ) != FLAC__STREAM_DECODER_INIT_STATUS_OK) do_something;
+ * \endcode
+ *
+ * Another small change to the decoder is in how it handles unparseable
+ * streams.  Before, when the decoder found an unparseable stream
+ * (reserved for when the decoder encounters a stream from a future
+ * encoder that it can't parse), it changed the state to
+ * \c FLAC__STREAM_DECODER_UNPARSEABLE_STREAM.  Now the decoder instead
+ * drops sync and calls the error callback with a new error code
+ * \c FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM.  This is
+ * more robust.  If your error callback does not discriminate on the the
+ * error state, your code does not need to be changed.
+ *
+ * The encoder now has a new setting:
+ * FLAC__stream_encoder_set_apodization().  This is for setting the
+ * method used to window the data before LPC analysis.  You only need to
+ * add a call to this function if the default is not suitable.   There
+ * are also two new convenience functions that may be useful:
+ * FLAC__metadata_object_cuesheet_calculate_cddb_id() and
+ * FLAC__metadata_get_cuesheet().
+ *
+ * The \a bytes parameter to FLAC__StreamDecoderReadCallback,
+ * FLAC__StreamEncoderReadCallback, and FLAC__StreamEncoderWriteCallback
+ * is now \c size_t instead of \c unsigned.
+ */
+
+/** \defgroup porting_1_1_3_to_1_1_4 Porting from FLAC 1.1.3 to 1.1.4
+ *  \ingroup porting
+ *
+ *  \brief
+ *  This module describes porting from FLAC 1.1.3 to FLAC 1.1.4.
+ *
+ * There were no changes to any of the interfaces from 1.1.3 to 1.1.4.
+ * There was a slight change in the implementation of
+ * FLAC__stream_encoder_set_metadata(); the function now makes a copy
+ * of the \a metadata array of pointers so the client no longer needs
+ * to maintain it after the call.  The objects themselves that are
+ * pointed to by the array are still not copied though and must be
+ * maintained until the call to FLAC__stream_encoder_finish().
+ */
+
+/** \defgroup porting_1_1_4_to_1_2_0 Porting from FLAC 1.1.4 to 1.2.0
+ *  \ingroup porting
+ *
+ *  \brief
+ *  This module describes porting from FLAC 1.1.4 to FLAC 1.2.0.
+ *
+ * There were only very minor changes to the interfaces from 1.1.4 to 1.2.0.
+ * In libFLAC, \c FLAC__format_sample_rate_is_subset() was added.
+ * In libFLAC++, \c FLAC::Decoder::Stream::get_decode_position() was added.
+ *
+ * Finally, value of the constant \c FLAC__FRAME_HEADER_RESERVED_LEN
+ * has changed to reflect the conversion of one of the reserved bits
+ * into active use.  It used to be \c 2 and now is \c 1.  However the
+ * FLAC frame header length has not changed, so to skip the proper
+ * number of bits, use \c FLAC__FRAME_HEADER_RESERVED_LEN +
+ * \c FLAC__FRAME_HEADER_BLOCKING_STRATEGY_LEN
  */
 
 /** \defgroup flac FLAC C API
--- a/sys/src/cmd/audio/libFLAC/FLAC/assert.h
+++ b/sys/src/cmd/audio/libFLAC/FLAC/assert.h
@@ -1,5 +1,6 @@
 /* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2001,2002,2003,2004  Josh Coalson
+ * Copyright (C) 2001-2009  Josh Coalson
+ * Copyright (C) 2011-2014  Xiph.Org Foundation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
--- a/sys/src/cmd/audio/libFLAC/FLAC/callback.h
+++ b/sys/src/cmd/audio/libFLAC/FLAC/callback.h
@@ -1,5 +1,6 @@
 /* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2004  Josh Coalson
+ * Copyright (C) 2004-2009  Josh Coalson
+ * Copyright (C) 2011-2014  Xiph.Org Foundation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -68,7 +69,7 @@
  *  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
+ *  is required.  \warning You generally CANNOT 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),
@@ -82,6 +83,9 @@
 extern "C" {
 #endif
 
+/** This is the opaque handle type used by the callbacks.  Typically
+ *  this is a \c FILE* or address of a file descriptor.
+ */
 typedef void* FLAC__IOHandle;
 
 /** Signature for the read callback.
--- a/sys/src/cmd/audio/libFLAC/FLAC/export.h
+++ b/sys/src/cmd/audio/libFLAC/FLAC/export.h
@@ -1,5 +1,6 @@
 /* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2000,2001,2002,2003,2004  Josh Coalson
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2014  Xiph.Org Foundation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -32,16 +33,65 @@
 #ifndef FLAC__EXPORT_H
 #define FLAC__EXPORT_H
 
-#if defined(FLAC__NO_DLL) || !defined(_MSC_VER)
+/** \file include/FLAC/export.h
+ *
+ *  \brief
+ *  This module contains #defines and symbols for exporting function
+ *  calls, and providing version information and compiled-in features.
+ *
+ *  See the \link flac_export export \endlink module.
+ */
+
+/** \defgroup flac_export FLAC/export.h: export symbols
+ *  \ingroup flac
+ *
+ *  \brief
+ *  This module contains #defines and symbols for exporting function
+ *  calls, and providing version information and compiled-in features.
+ *
+ *  If you are compiling with MSVC and will link to the static library
+ *  (libFLAC.lib) you should define FLAC__NO_DLL in your project to
+ *  make sure the symbols are exported properly.
+ *
+ * \{
+ */
+
+#if defined(FLAC__NO_DLL)
 #define FLAC_API
 
+#elif defined(_MSC_VER)
+#ifdef FLAC_API_EXPORTS
+#define	FLAC_API __declspec(dllexport)
 #else
+#define FLAC_API __declspec(dllimport)
+#endif
 
-#ifdef FLAC_API_EXPORTS
-#define	FLAC_API	_declspec(dllexport)
+#elif defined(FLAC__USE_VISIBILITY_ATTR)
+#define FLAC_API __attribute__ ((visibility ("default")))
+
 #else
-#define FLAC_API	_declspec(dllimport)
+#define FLAC_API
 
 #endif
+
+/** These #defines will mirror the libtool-based library version number, see
+ * http://www.gnu.org/software/libtool/manual/libtool.html#Libtool-versioning
+ */
+#define FLAC_API_VERSION_CURRENT 11
+#define FLAC_API_VERSION_REVISION 0 /**< see above */
+#define FLAC_API_VERSION_AGE 3 /**< see above */
+
+#ifdef __cplusplus
+extern "C" {
 #endif
+
+/** \c 1 if the library has been compiled with support for Ogg FLAC, else \c 0. */
+extern FLAC_API int FLAC_API_SUPPORTS_OGG_FLAC;
+
+#ifdef __cplusplus
+}
+#endif
+
+/* \} */
+
 #endif
--- a/sys/src/cmd/audio/libFLAC/FLAC/file_decoder.h
+++ /dev/null
@@ -1,660 +1,0 @@
-/* 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
--- a/sys/src/cmd/audio/libFLAC/FLAC/file_encoder.h
+++ /dev/null
@@ -1,871 +1,0 @@
-/* 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
--- a/sys/src/cmd/audio/libFLAC/FLAC/format.h
+++ b/sys/src/cmd/audio/libFLAC/FLAC/format.h
@@ -1,5 +1,6 @@
 /* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2000,2001,2002,2003,2004  Josh Coalson
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2014  Xiph.Org Foundation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -97,6 +98,10 @@
 /** The maximum block size, in samples, permitted by the format. */
 #define FLAC__MAX_BLOCK_SIZE (65535u)
 
+/** The maximum block size, in samples, permitted by the FLAC subset for
+ *  sample rates up to 48kHz. */
+#define FLAC__SUBSET_MAX_BLOCK_SIZE_48000HZ (4608u)
+
 /** The maximum number of channels permitted by the format. */
 #define FLAC__MAX_CHANNELS (8u)
 
@@ -125,6 +130,10 @@
 /** The maximum LPC order permitted by the format. */
 #define FLAC__MAX_LPC_ORDER (32u)
 
+/** The maximum LPC order permitted by the FLAC subset for sample rates
+ *  up to 48kHz. */
+#define FLAC__SUBSET_MAX_LPC_ORDER_48000HZ (12u)
+
 /** The minimum quantized linear predictor coefficient precision
  *  permitted by the format.
  */
@@ -153,7 +162,7 @@
 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
+ *  This is a NUL-terminated ASCII string; when inserted into the
  *  VORBIS_COMMENT the trailing null is stripped.
  */
 extern FLAC_API const char *FLAC__VENDOR_STRING;
@@ -183,9 +192,13 @@
 
 /** An enumeration of the available entropy coding methods. */
 typedef enum {
-	FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE = 0
+	FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE = 0,
 	/**< Residual is coded by partitioning into contexts, each with it's own
-	 * Rice parameter. */
+	 * 4-bit Rice parameter. */
+
+	FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2 = 1
+	/**< Residual is coded by partitioning into contexts, each with it's own
+	 * 5-bit Rice parameter. */
 } FLAC__EntropyCodingMethodType;
 
 /** Maps a FLAC__EntropyCodingMethodType to a C string.
@@ -204,7 +217,9 @@
 	/**< The Rice parameters for each context. */
 
 	unsigned *raw_bits;
-	/**< Widths for escape-coded partitions. */
+	/**< Widths for escape-coded partitions.  Will be non-zero for escaped
+	 * partitions and zero for unescaped partitions.
+	 */
 
 	unsigned capacity_by_order;
 	/**< The capacity of the \a parameters and \a raw_bits arrays
@@ -227,10 +242,13 @@
 
 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_RICE2_PARAMETER_LEN; /**< == 5 (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 */
+extern FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER;
+/**< == (1<<FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN)-1 */
 
 /** Header for the entropy coding method.  (c.f. <A HREF="../format.html#residual">format specification</A>)
  */
@@ -334,14 +352,21 @@
 	unsigned wasted_bits;
 } FLAC__Subframe;
 
-extern FLAC_API const unsigned FLAC__SUBFRAME_ZERO_PAD_LEN; /**< == 1 (bit) */
+/** == 1 (bit)
+ *
+ * This used to be a zero-padding bit (hence the name
+ * FLAC__SUBFRAME_ZERO_PAD_LEN) but is now a reserved bit.  It still has a
+ * mandatory value of \c 0 but in the future may take on the value \c 0 or \c 1
+ * to mean something else.
+ */
+extern FLAC_API const unsigned FLAC__SUBFRAME_ZERO_PAD_LEN;
 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 */
+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 */
 
 /*****************************************************************************/
 
@@ -400,7 +425,9 @@
 	/**< The sample resolution. */
 
 	FLAC__FrameNumberType number_type;
-	/**< The numbering scheme used for the frame. */
+	/**< The numbering scheme used for the frame.  As a convenience, the
+	 * decoder will always convert a frame number to a sample number because
+	 * the rules are complex. */
 
 	union {
 		FLAC__uint32 frame_number;
@@ -418,7 +445,8 @@
 
 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_RESERVED_LEN; /**< == 1 (bits) */
+extern FLAC_API const unsigned FLAC__FRAME_HEADER_BLOCKING_STRATEGY_LEN; /**< == 1 (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) */
@@ -473,14 +501,19 @@
 	/**< <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 */
+	/**< <A HREF="../format.html#metadata_block_vorbis_comment">VORBISCOMMENT</A> block (a.k.a. FLAC tags) */
 
 	FLAC__METADATA_TYPE_CUESHEET = 5,
 	/**< <A HREF="../format.html#metadata_block_cuesheet">CUESHEET</A> block */
 
-	FLAC__METADATA_TYPE_UNDEFINED = 6
+	FLAC__METADATA_TYPE_PICTURE = 6,
+	/**< <A HREF="../format.html#metadata_block_picture">PICTURE</A> block */
+
+	FLAC__METADATA_TYPE_UNDEFINED = 7,
 	/**< marker to denote beginning of undefined type range; this number will increase as new metadata types are added */
 
+        FLAC__MAX_METADATA_TYPE = FLAC__MAX_METADATA_TYPE_CODE,
+        /**< No type will ever be greater than this. There is not enough room in the protocol block. */
 } FLAC__MetadataType;
 
 /** Maps a FLAC__MetadataType to a C string.
@@ -583,6 +616,10 @@
 
 
 /** Vorbis comment entry structure used in VORBIS_COMMENT blocks.  (c.f. <A HREF="../format.html#metadata_block_vorbis_comment">format specification</A>)
+ *
+ *  For convenience, the APIs maintain a trailing NUL character at the end of
+ *  \a entry which is not counted toward \a length, i.e.
+ *  \code strlen(entry) == length \endcode
  */
 typedef struct {
 	FLAC__uint32 length;
@@ -634,7 +671,7 @@
 	/**< The track number. */
 
 	char isrc[13];
-	/**< Track ISRC.  This is a 12-digit alphanumeric code plus a trailing '\0' */
+	/**< Track ISRC.  This is a 12-digit alphanumeric code plus a trailing \c NUL byte */
 
 	unsigned type:1;
 	/**< The track type: 0 for audio, 1 for non-audio. */
@@ -674,7 +711,7 @@
 	/**< The number of lead-in samples. */
 
 	FLAC__bool is_cd;
-	/**< \c true if CUESHEET corresponds to a Compact Disc, else \c false */
+	/**< \c true if CUESHEET corresponds to a Compact Disc, else \c false. */
 
 	unsigned num_tracks;
 	/**< The number of tracks. */
@@ -691,6 +728,98 @@
 extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN; /**< == 8 (bits) */
 
 
+/** An enumeration of the PICTURE types (see FLAC__StreamMetadataPicture and id3 v2.4 APIC tag). */
+typedef enum {
+	FLAC__STREAM_METADATA_PICTURE_TYPE_OTHER = 0, /**< Other */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON_STANDARD = 1, /**< 32x32 pixels 'file icon' (PNG only) */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON = 2, /**< Other file icon */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER = 3, /**< Cover (front) */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_BACK_COVER = 4, /**< Cover (back) */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_LEAFLET_PAGE = 5, /**< Leaflet page */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_MEDIA = 6, /**< Media (e.g. label side of CD) */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_LEAD_ARTIST = 7, /**< Lead artist/lead performer/soloist */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_ARTIST = 8, /**< Artist/performer */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_CONDUCTOR = 9, /**< Conductor */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_BAND = 10, /**< Band/Orchestra */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_COMPOSER = 11, /**< Composer */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_LYRICIST = 12, /**< Lyricist/text writer */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_RECORDING_LOCATION = 13, /**< Recording Location */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_DURING_RECORDING = 14, /**< During recording */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_DURING_PERFORMANCE = 15, /**< During performance */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_VIDEO_SCREEN_CAPTURE = 16, /**< Movie/video screen capture */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_FISH = 17, /**< A bright coloured fish */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_ILLUSTRATION = 18, /**< Illustration */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_BAND_LOGOTYPE = 19, /**< Band/artist logotype */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_PUBLISHER_LOGOTYPE = 20, /**< Publisher/Studio logotype */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_UNDEFINED
+} FLAC__StreamMetadata_Picture_Type;
+
+/** Maps a FLAC__StreamMetadata_Picture_Type to a C string.
+ *
+ *  Using a FLAC__StreamMetadata_Picture_Type as the index to this array
+ *  will give the string equivalent.  The contents should not be
+ *  modified.
+ */
+extern FLAC_API const char * const FLAC__StreamMetadata_Picture_TypeString[];
+
+/** FLAC PICTURE structure.  (See the
+ * <A HREF="../format.html#metadata_block_picture">format specification</A>
+ * for the full description of each field.)
+ */
+typedef struct {
+	FLAC__StreamMetadata_Picture_Type type;
+	/**< The kind of picture stored. */
+
+	char *mime_type;
+	/**< Picture data's MIME type, in ASCII printable characters
+	 * 0x20-0x7e, NUL terminated.  For best compatibility with players,
+	 * use picture data of MIME type \c image/jpeg or \c image/png.  A
+	 * MIME type of '-->' is also allowed, in which case the picture
+	 * data should be a complete URL.  In file storage, the MIME type is
+	 * stored as a 32-bit length followed by the ASCII string with no NUL
+	 * terminator, but is converted to a plain C string in this structure
+	 * for convenience.
+	 */
+
+	FLAC__byte *description;
+	/**< Picture's description in UTF-8, NUL terminated.  In file storage,
+	 * the description is stored as a 32-bit length followed by the UTF-8
+	 * string with no NUL terminator, but is converted to a plain C string
+	 * in this structure for convenience.
+	 */
+
+	FLAC__uint32 width;
+	/**< Picture's width in pixels. */
+
+	FLAC__uint32 height;
+	/**< Picture's height in pixels. */
+
+	FLAC__uint32 depth;
+	/**< Picture's color depth in bits-per-pixel. */
+
+	FLAC__uint32 colors;
+	/**< For indexed palettes (like GIF), picture's number of colors (the
+	 * number of palette entries), or \c 0 for non-indexed (i.e. 2^depth).
+	 */
+
+	FLAC__uint32 data_length;
+	/**< Length of binary picture data in bytes. */
+
+	FLAC__byte *data;
+	/**< Binary picture data. */
+
+} FLAC__StreamMetadata_Picture;
+
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_TYPE_LEN; /**< == 32 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN; /**< == 32 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN; /**< == 32 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN; /**< == 32 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN; /**< == 32 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN; /**< == 32 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_COLORS_LEN; /**< == 32 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN; /**< == 32 (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.
@@ -721,6 +850,7 @@
 		FLAC__StreamMetadata_SeekTable seek_table;
 		FLAC__StreamMetadata_VorbisComment vorbis_comment;
 		FLAC__StreamMetadata_CueSheet cue_sheet;
+		FLAC__StreamMetadata_Picture picture;
 		FLAC__StreamMetadata_Unknown unknown;
 	} data;
 	/**< Polymorphic block data; use the \a type value to determine which
@@ -743,9 +873,7 @@
  *
  *****************************************************************************/
 
-/* @@@@ 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.
+/** Tests that a sample rate is valid for FLAC.
  *
  * \param sample_rate  The sample rate to test for compliance.
  * \retval FLAC__bool
@@ -754,7 +882,76 @@
  */
 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 */
+/** Tests that a blocksize at the given sample rate is valid for the FLAC
+ *  subset.
+ *
+ * \param blocksize    The blocksize to test for compliance.
+ * \param sample_rate  The sample rate is needed, since the valid subset
+ *                     blocksize depends on the sample rate.
+ * \retval FLAC__bool
+ *    \c true if the given blocksize conforms to the specification for the
+ *    subset at the given sample rate, else \c false.
+ */
+FLAC_API FLAC__bool FLAC__format_blocksize_is_subset(unsigned blocksize, unsigned sample_rate);
+
+/** Tests that a sample rate is valid for the FLAC subset.  The subset rules
+ *  for valid sample rates are slightly more complex since the rate has to
+ *  be expressible completely in the frame header.
+ *
+ * \param sample_rate  The sample rate to test for compliance.
+ * \retval FLAC__bool
+ *    \c true if the given sample rate conforms to the specification for the
+ *    subset, else \c false.
+ */
+FLAC_API FLAC__bool FLAC__format_sample_rate_is_subset(unsigned sample_rate);
+
+/** Check a Vorbis comment entry name to see if it conforms to the Vorbis
+ *  comment specification.
+ *
+ *  Vorbis comment names must be composed only of characters from
+ *  [0x20-0x3C,0x3E-0x7D].
+ *
+ * \param name       A NUL-terminated string to be checked.
+ * \assert
+ *    \code name != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if entry name is illegal, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_name_is_legal(const char *name);
+
+/** Check a Vorbis comment entry value to see if it conforms to the Vorbis
+ *  comment specification.
+ *
+ *  Vorbis comment values must be valid UTF-8 sequences.
+ *
+ * \param value      A string to be checked.
+ * \param length     A the length of \a value in bytes.  May be
+ *                   \c (unsigned)(-1) to indicate that \a value is a plain
+ *                   UTF-8 NUL-terminated string.
+ * \assert
+ *    \code value != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if entry name is illegal, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_value_is_legal(const FLAC__byte *value, unsigned length);
+
+/** Check a Vorbis comment entry to see if it conforms to the Vorbis
+ *  comment specification.
+ *
+ *  Vorbis comment entries must be of the form 'name=value', and 'name' and
+ *  'value' must be legal according to
+ *  FLAC__format_vorbiscomment_entry_name_is_legal() and
+ *  FLAC__format_vorbiscomment_entry_value_is_legal() respectively.
+ *
+ * \param entry      An entry to be checked.
+ * \param length     The length of \a entry in bytes.
+ * \assert
+ *    \code value != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if entry name is illegal, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_is_legal(const FLAC__byte *entry, unsigned length);
+
 /** 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.
@@ -767,7 +964,6 @@
  */
 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
@@ -782,7 +978,6 @@
  */
 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.
@@ -802,6 +997,24 @@
  *    \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);
+
+/** Check picture data to see if it conforms to the FLAC specification.
+ *  See the format specification for limits on the contents of the
+ *  PICTURE block.
+ *
+ * \param picture    A pointer to existing picture data to be checked.
+ * \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 picture != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if picture data is illegal, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__format_picture_is_legal(const FLAC__StreamMetadata_Picture *picture, const char **violation);
 
 /* \} */
 
--- a/sys/src/cmd/audio/libFLAC/FLAC/metadata.h
+++ b/sys/src/cmd/audio/libFLAC/FLAC/metadata.h
@@ -1,5 +1,6 @@
 /* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2001,2002,2003,2004  Josh Coalson
+ * Copyright (C) 2001-2009  Josh Coalson
+ * Copyright (C) 2011-2014  Xiph.Org Foundation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -32,15 +33,16 @@
 #ifndef FLAC__METADATA_H
 #define FLAC__METADATA_H
 
+#include <sys/types.h> /* for off_t */
 #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/)
-******************************************************************************/
+/* --------------------------------------------------------------------
+   (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
  *
@@ -59,12 +61,16 @@
  *  \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.
+ *  interfaces for traversing and editing metadata in native FLAC files.
+ *  Note that currently only the Chain interface (level 2) supports Ogg
+ *  FLAC files, and it is read-only i.e. no writing back changed
+ *  metadata to file.
  *
  *  There are three metadata interfaces of increasing complexity:
  *
  *  Level 0:
- *  Read-only access to the STREAMINFO and VORBIS_COMMENT blocks.
+ *  Read-only access to the STREAMINFO, VORBIS_COMMENT, CUESHEET, and
+ *  PICTURE blocks.
  *
  *  Level 1:
  *  Read-write access to all metadata blocks.  This level is write-
@@ -96,7 +102,8 @@
  *
  *  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.
+ *  handle and callbacks, for situations where 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
@@ -124,15 +131,16 @@
  *
  *  \brief
  *  The level 0 interface consists of individual routines to read the
- *  STREAMINFO and VORBIS_COMMENT blocks, requiring only a filename.
+ *  STREAMINFO, VORBIS_COMMENT, CUESHEET, and PICTURE blocks, requiring
+ *  only a filename.
  *
- *  It skips any ID3v2 tag at the head of the file.
+ *  They try to skip 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.
+ *  will try to 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
@@ -151,7 +159,7 @@
 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.
+ *  function will try to 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
@@ -159,10 +167,10 @@
  *                    the caller using FLAC__metadata_object_delete().
  * \assert
  *    \code filename != NULL \endcode
- *    \code streaminfo != NULL \endcode
+ *    \code tags != 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.
+ *    and \a *tags will be set to the address of the metadata 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.
@@ -169,6 +177,65 @@
  */
 FLAC_API FLAC__bool FLAC__metadata_get_tags(const char *filename, FLAC__StreamMetadata **tags);
 
+/** Read the CUESHEET metadata block of the given FLAC file.  This
+ *  function will try to skip any ID3v2 tag at the head of the file.
+ *
+ * \param filename    The path to the FLAC file to read.
+ * \param cuesheet    The address where the returned pointer will be
+ *                    stored.  The \a cuesheet object must be deleted by
+ *                    the caller using FLAC__metadata_object_delete().
+ * \assert
+ *    \code filename != NULL \endcode
+ *    \code cuesheet != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if a valid CUESHEET block was read from \a filename,
+ *    and \a *cuesheet will be set to the address of the metadata
+ *    structure.  Returns \c false if there was a memory allocation
+ *    error, a file decoder error, or the file contained no CUESHEET
+ *    block, and \a *cuesheet will be set to \c NULL.
+ */
+FLAC_API FLAC__bool FLAC__metadata_get_cuesheet(const char *filename, FLAC__StreamMetadata **cuesheet);
+
+/** Read a PICTURE metadata block of the given FLAC file.  This
+ *  function will try to skip any ID3v2 tag at the head of the file.
+ *  Since there can be more than one PICTURE block in a file, this
+ *  function takes a number of parameters that act as constraints to
+ *  the search.  The PICTURE block with the largest area matching all
+ *  the constraints will be returned, or \a *picture will be set to
+ *  \c NULL if there was no such block.
+ *
+ * \param filename    The path to the FLAC file to read.
+ * \param picture     The address where the returned pointer will be
+ *                    stored.  The \a picture object must be deleted by
+ *                    the caller using FLAC__metadata_object_delete().
+ * \param type        The desired picture type.  Use \c -1 to mean
+ *                    "any type".
+ * \param mime_type   The desired MIME type, e.g. "image/jpeg".  The
+ *                    string will be matched exactly.  Use \c NULL to
+ *                    mean "any MIME type".
+ * \param description The desired description.  The string will be
+ *                    matched exactly.  Use \c NULL to mean "any
+ *                    description".
+ * \param max_width   The maximum width in pixels desired.  Use
+ *                    \c (unsigned)(-1) to mean "any width".
+ * \param max_height  The maximum height in pixels desired.  Use
+ *                    \c (unsigned)(-1) to mean "any height".
+ * \param max_depth   The maximum color depth in bits-per-pixel desired.
+ *                    Use \c (unsigned)(-1) to mean "any depth".
+ * \param max_colors  The maximum number of colors desired.  Use
+ *                    \c (unsigned)(-1) to mean "any number of colors".
+ * \assert
+ *    \code filename != NULL \endcode
+ *    \code picture != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if a valid PICTURE block was read from \a filename,
+ *    and \a *picture will be set to the address of the metadata
+ *    structure.  Returns \c false if there was a memory allocation
+ *    error, a file decoder error, or the file contained no PICTURE
+ *    block, and \a *picture will be set to \c NULL.
+ */
+FLAC_API FLAC__bool FLAC__metadata_get_picture(const char *filename, FLAC__StreamMetadata **picture, FLAC__StreamMetadata_Picture_Type type, const char *mime_type, const FLAC__byte *description, unsigned max_width, unsigned max_height, unsigned max_depth, unsigned max_colors);
+
 /* \} */
 
 
@@ -184,9 +251,9 @@
  * - 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.
+ *   see if the file is writable, or only read access is allowed.
  * - Use FLAC__metadata_simple_iterator_next() and
- *   FLAC__metadata_simple_iterator_prev() to move around the blocks.
+ *   FLAC__metadata_simple_iterator_prev() to traverse 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
@@ -295,7 +362,7 @@
  * \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();
+FLAC_API FLAC__Metadata_SimpleIterator *FLAC__metadata_simple_iterator_new(void);
 
 /** Free an iterator instance.  Deletes the object pointed to by \a iterator.
  *
@@ -378,6 +445,35 @@
  */
 FLAC_API FLAC__bool FLAC__metadata_simple_iterator_prev(FLAC__Metadata_SimpleIterator *iterator);
 
+/** Returns a flag telling if the current metadata block is the last.
+ *
+ * \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 true if the current metadata block is the last in the file,
+ *    else \c false.
+ */
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_is_last(const FLAC__Metadata_SimpleIterator *iterator);
+
+/** Get the offset 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 off_t
+ *    The offset of the metadata block at the current iterator position.
+ *    This is the byte offset relative to the beginning of the file of
+ *    the current metadata block's header.
+ */
+FLAC_API off_t FLAC__metadata_simple_iterator_get_block_offset(const 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.
@@ -390,9 +486,50 @@
  * \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 length 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 unsigned
+ *    The length of the metadata block at the current iterator position.
+ *    The is same length as that in the
+ *    <a href="http://xiph.org/flac/format.html#metadata_block_header">metadata block header</a>,
+ *    i.e. the length of the metadata body that follows the header.
+ */
+FLAC_API unsigned FLAC__metadata_simple_iterator_get_block_length(const FLAC__Metadata_SimpleIterator *iterator);
+
+/** Get the application ID of the \c APPLICATION 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.
+ * \param id        A pointer to a buffer of at least \c 4 bytes where
+ *                  the ID will be stored.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \code id != NULL \endcode
+ *    \a iterator has been successfully initialized with
+ *    FLAC__metadata_simple_iterator_init()
+ * \retval FLAC__bool
+ *    \c true if the ID was successfully read, else \c false, in which
+ *    case you should check FLAC__metadata_simple_iterator_status() to
+ *    find out why.  If the status is
+ *    \c FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT, then the
+ *    current metadata block is not an \c APPLICATION block.  Otherwise
+ *    if the status is
+ *    \c FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR or
+ *    \c FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR, an I/O error
+ *    occurred and the iterator can no longer be used.
+ */
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_get_application_id(FLAC__Metadata_SimpleIterator *iterator, FLAC__byte *id);
+
 /** 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.
@@ -406,7 +543,8 @@
  *    \a iterator has been successfully initialized with
  *    FLAC__metadata_simple_iterator_init()
  * \retval FLAC__StreamMetadata*
- *    The current metadata block.
+ *    The current metadata block, or \c NULL if there was a memory
+ *    allocation error.
  */
 FLAC_API FLAC__StreamMetadata *FLAC__metadata_simple_iterator_get_block(FLAC__Metadata_SimpleIterator *iterator);
 
@@ -521,12 +659,17 @@
  * 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.
  *
+ * Currently Ogg FLAC is supported for read only, via
+ * FLAC__metadata_chain_read_ogg() but a subsequent
+ * FLAC__metadata_chain_write() will fail.
+ *
  * 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.
+ *   FLAC__metadata_chain_read() or FLAC__metadata_chain_read_ogg() and
+ *   check the status.
  * - Optionally, consolidate the padding using
  *   FLAC__metadata_chain_merge_padding() or
  *   FLAC__metadata_chain_sort_padding().
@@ -548,8 +691,8 @@
  * 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().
+ * between the time of FLAC__metadata_chain_read()/FLAC__metadata_chain_read_ogg()
+ * and FLAC__metadata_chain_write().
  *
  * \note
  * Do not modify the is_last, length, or type fields of returned
@@ -620,11 +763,12 @@
 
 	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_read_with_callbacks()/FLAC__metadata_chain_read_ogg_with_callbacks(),
+	 *   or 
+	 *   FLAC__metadata_chain_write_with_callbacks()/FLAC__metadata_chain_write_with_callbacks_and_tempfile()
+	 *   was called on a chain read by
+	 *   FLAC__metadata_chain_read()/FLAC__metadata_chain_read_ogg().
+	 *   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
@@ -652,7 +796,7 @@
  * \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();
+FLAC_API FLAC__Metadata_Chain *FLAC__metadata_chain_new(void);
 
 /** Free a chain instance.  Deletes the object pointed to by \a chain.
  *
@@ -688,6 +832,23 @@
  */
 FLAC_API FLAC__bool FLAC__metadata_chain_read(FLAC__Metadata_Chain *chain, const char *filename);
 
+/** Read all metadata from an Ogg FLAC file into the chain.
+ *
+ * \note Ogg FLAC metadata data writing is not supported yet and
+ * FLAC__metadata_chain_write() will fail.
+ *
+ * \param chain    A pointer to an existing chain.
+ * \param filename The path to the Ogg 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_ogg(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.
@@ -710,6 +871,31 @@
  */
 FLAC_API FLAC__bool FLAC__metadata_chain_read_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks);
 
+/** Read all metadata from an Ogg 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).
+ *
+ * \note Ogg FLAC metadata data writing is not supported yet and
+ * FLAC__metadata_chain_write() will fail.
+ *
+ * \param chain    A pointer to an existing chain.
+ * \param handle   The I/O handle of the Ogg 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_ogg_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.
  *
@@ -770,7 +956,8 @@
  *  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().
+ *  FLAC__metadata_chain_read()/FLAC__metadata_chain_read_ogg(), not
+ *  FLAC__metadata_chain_read_with_callbacks()/FLAC__metadata_chain_read_ogg_with_callbacks().
  *
  * \param chain               A pointer to an existing chain.
  * \param use_padding         See above.
@@ -793,7 +980,8 @@
  *  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().
+ *  FLAC__metadata_chain_read_with_callbacks()/FLAC__metadata_chain_read_ogg_with_callbacks(),
+ *  not FLAC__metadata_chain_read()/FLAC__metadata_chain_read_ogg().
  *  Also, FLAC__metadata_chain_check_if_tempfile_needed() must have returned
  *  \c false.
  *
@@ -836,7 +1024,8 @@
  *  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().
+ *  FLAC__metadata_chain_read_with_callbacks()/FLAC__metadata_chain_read_ogg_with_callbacks(),
+ *  not FLAC__metadata_chain_read()/FLAC__metadata_chain_read_ogg().
  *  Also, FLAC__metadata_chain_check_if_tempfile_needed() must have returned
  *  \c true.
  *
@@ -899,7 +1088,7 @@
  * \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();
+FLAC_API FLAC__Metadata_Iterator *FLAC__metadata_iterator_new(void);
 
 /** Free an iterator instance.  Deletes the object pointed to by \a iterator.
  *
@@ -1087,6 +1276,17 @@
  * FLAC__metadata_object_application_set_data(), you will get an assertion
  * failure.
  *
+ * For convenience the FLAC__metadata_object_vorbiscomment_*() functions
+ * maintain a trailing NUL on each Vorbis comment entry.  This is not counted
+ * toward the length or stored in the stream, but it can make working with plain
+ * comments (those that don't contain embedded-NULs in the value) easier.
+ * Entries passed into these functions have trailing NULs added if missing, and
+ * returned entries are guaranteed to have a trailing NUL.
+ *
+ * The FLAC__metadata_object_vorbiscomment_*() functions that take a Vorbis
+ * comment entry/name/value will first validate that it complies with the Vorbis
+ * comment specification and return false if it does not.
+ *
  * 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.
@@ -1155,9 +1355,12 @@
 /** 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.
+ *  takes ownership of the pointer.  The existing data will be freed if this
+ *  function is successful, otherwise the original data will remain if \a copy
+ *  is \c true and malloc() fails.
  *
+ * \note It is safe to pass a const pointer to \a data if \a copy is \c true.
+ *
  * \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.
@@ -1168,7 +1371,7 @@
  *    \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.
+ *    \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);
 
@@ -1309,11 +1512,40 @@
  * \assert
  *    \code object != NULL \endcode
  *    \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ *    \code total_samples > 0 \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);
 
+/** 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 samples The number of samples apart to space the placeholder
+ *                points.  The first point will be at sample \c 0, the
+ *                second at sample \a samples, then 2*\a samples, and
+ *                so on.  As long as \a samples and \a total_samples
+ *                are greater than \c 0, there will always be at least
+ *                one seekpoint at sample \c 0.
+ * \param total_samples  The total number of samples to be encoded;
+ *                       the seekpoints will be spaced
+ *                       \a samples samples apart.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ *    \code samples > 0 \endcode
+ *    \code total_samples > 0 \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_by_samples(FLAC__StreamMetadata *object, unsigned samples, FLAC__uint64 total_samples);
+
 /** Sort a seek table's seek points according to the format specification,
  *  removing duplicates.
  *
@@ -1327,16 +1559,21 @@
  *    \code object != NULL \endcode
  *    \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
  * \retval FLAC__bool
- *    \c false if realloc fails, else \c true.
+ *    \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.
  *
+ *  For convenience, a trailing NUL is added to the entry if it doesn't have
+ *  one already.
+ *
  *  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.
+ *  takes ownership of the \c entry.entry pointer.
  *
+ *  \note If this function returns \c false, the caller still owns the
+ *  pointer.
+ *
  * \param object  A pointer to an existing VORBIS_COMMENT object.
  * \param entry   The entry to set the vendor string to.
  * \param copy    See above.
@@ -1343,10 +1580,11 @@
  * \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
+ *    \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.
+ *    \c false if memory allocation fails or \a entry does not comply with the
+ *    Vorbis comment specification, 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);
 
@@ -1363,16 +1601,21 @@
  *    \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.
+ *    \c false if memory allocation fails, 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.
  *
+ *  For convenience, a trailing NUL is added to the entry if it doesn't have
+ *  one already.
+ *
  *  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.
+ *  takes ownership of the \c entry.entry pointer.
  *
+ *  \note If this function returns \c false, the caller still owns the
+ *  pointer.
+ *
  * \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.
@@ -1381,19 +1624,25 @@
  *    \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
+ *    \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.
+ *    \c false if memory allocation fails or \a entry does not comply with the
+ *    Vorbis comment specification, 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.
  *
+ *  For convenience, a trailing NUL is added to the entry if it doesn't have
+ *  one already.
+ *
  *  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.
+ *  takes ownership of the \c entry.entry pointer.
  *
+ *  \note If this function returns \c false, the caller still owns the
+ *  pointer.
+ *
  * \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.
@@ -1405,13 +1654,74 @@
  *    \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
+ *    \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.
+ *    \c false if memory allocation fails or \a entry does not comply with the
+ *    Vorbis comment specification, 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);
 
+/** Appends a comment to a VORBIS_COMMENT block.
+ *
+ *  For convenience, a trailing NUL is added to the entry if it doesn't have
+ *  one already.
+ *
+ *  If \a copy is \c true, a copy of the entry is stored; otherwise, the object
+ *  takes ownership of the \c entry.entry pointer.
+ *
+ *  \note If this function returns \c false, the caller still owns the
+ *  pointer.
+ *
+ * \param object       A pointer to an existing VORBIS_COMMENT object.
+ * \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 (entry.entry != NULL && entry.length > 0) ||
+ * (entry.entry == NULL && entry.length == 0 && copy == false) \endcode
+ * \retval FLAC__bool
+ *    \c false if memory allocation fails or \a entry does not comply with the
+ *    Vorbis comment specification, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_append_comment(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy);
+
+/** Replaces comments in a VORBIS_COMMENT block with a new one.
+ *
+ *  For convenience, a trailing NUL is added to the entry if it doesn't have
+ *  one already.
+ *
+ *  Depending on the the value of \a all, either all or just the first comment
+ *  whose field name(s) match the given entry's name will be replaced by the
+ *  given entry.  If no comments match, \a entry will simply be appended.
+ *
+ *  If \a copy is \c true, a copy of the entry is stored; otherwise, the object
+ *  takes ownership of the \c entry.entry pointer.
+ *
+ *  \note If this function returns \c false, the caller still owns the
+ *  pointer.
+ *
+ * \param object       A pointer to an existing VORBIS_COMMENT object.
+ * \param entry        The comment to insert.
+ * \param all          If \c true, all comments whose field name matches
+ *                     \a entry's field name will be removed, and \a entry will
+ *                     be inserted at the position of the first matching
+ *                     comment.  If \c false, only the first comment whose
+ *                     field name matches \a entry's field name will be
+ *                     replaced with \a entry.
+ * \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 && copy == false) \endcode
+ * \retval FLAC__bool
+ *    \c false if memory allocation fails or \a entry does not comply with the
+ *    Vorbis comment specification, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_replace_comment(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool all, 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.
@@ -1420,30 +1730,67 @@
  *    \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.
+ *    \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 */
+/** Creates a Vorbis comment entry from NUL-terminated name and value strings.
+ *
+ *  On return, the filled-in \a entry->entry pointer will point to malloc()ed
+ *  memory and shall be owned by the caller.  For convenience the entry will
+ *  have a terminating NUL.
+ *
+ * \param entry              A pointer to a Vorbis comment entry.  The entry's
+ *                           \c entry pointer should not point to allocated
+ *                           memory as it will be overwritten.
+ * \param field_name         The field name in ASCII, \c NUL terminated.
+ * \param field_value        The field value in UTF-8, \c NUL terminated.
+ * \assert
+ *    \code entry != NULL \endcode
+ *    \code field_name != NULL \endcode
+ *    \code field_value != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if malloc() fails, or if \a field_name or \a field_value does
+ *    not comply with the Vorbis comment specification, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(FLAC__StreamMetadata_VorbisComment_Entry *entry, const char *field_name, const char *field_value);
+
+/** Splits a Vorbis comment entry into NUL-terminated name and value strings.
+ *
+ *  The returned pointers to name and value will be allocated by malloc()
+ *  and shall be owned by the caller.
+ *
+ * \param entry              An existing Vorbis comment entry.
+ * \param field_name         The address of where the returned pointer to the
+ *                           field name will be stored.
+ * \param field_value        The address of where the returned pointer to the
+ *                           field value will be stored.
+ * \assert
+ *    \code (entry.entry != NULL && entry.length > 0) \endcode
+ *    \code memchr(entry.entry, '=', entry.length) != NULL \endcode
+ *    \code field_name != NULL \endcode
+ *    \code field_value != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if memory allocation fails or \a entry does not comply with the
+ *    Vorbis comment specification, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_to_name_value_pair(const FLAC__StreamMetadata_VorbisComment_Entry entry, char **field_name, char **field_value);
+
 /** 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 entry              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.
+ *                           terminating \c NUL.
  * \assert
- *    \code entry != NULL \endcode
- *    \code (entry->entry != NULL && entry->length > 0) \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);
+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
@@ -1456,6 +1803,7 @@
  * \assert
  *    \code object != NULL \endcode
  *    \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
+ *    \code field_name != NULL \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.
@@ -1462,7 +1810,6 @@
  */
 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.
@@ -1476,7 +1823,6 @@
  */
 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.
@@ -1497,7 +1843,7 @@
  * \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();
+FLAC_API FLAC__StreamMetadata_CueSheet_Track *FLAC__metadata_object_cuesheet_track_new(void);
 
 /** Create a copy of an existing CUESHEET track object.
  *
@@ -1561,7 +1907,7 @@
  *    \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.
+ *    \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);
 
@@ -1585,7 +1931,7 @@
  *    \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.
+ *    \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);
 
@@ -1604,7 +1950,7 @@
  *    \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.
+ *    \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);
 
@@ -1628,8 +1974,7 @@
 /** 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.
+ *  takes ownership of the \a track pointer.
  *
  * \param object       A pointer to an existing CUESHEET object.
  * \param track_num    Index into track array to set.  NOTE: this is not
@@ -1642,9 +1987,9 @@
  *    \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)
+ * (track->indices == NULL && track->num_indices == 0) \endcode
  * \retval FLAC__bool
- *    \c false if \a copy is \c true and malloc fails, else \c true.
+ *    \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);
 
@@ -1651,8 +1996,7 @@
 /** 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.
+ *  takes ownership of the \a track pointer.
  *
  * \param object       A pointer to an existing CUESHEET object.
  * \param track_num    The index at which to insert the track.  NOTE: this
@@ -1668,7 +2012,7 @@
  *    \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.
+ *    \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);
 
@@ -1687,7 +2031,7 @@
  *    \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.
+ *    \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);
 
@@ -1702,7 +2046,7 @@
  *    \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.
+ *    \c false if realloc() fails, else \c true.
  */
 FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_delete_track(FLAC__StreamMetadata *object, unsigned track_num);
 
@@ -1726,6 +2070,108 @@
  *    \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);
+
+/** Calculate and return the CDDB/freedb ID for a cue sheet.  The function
+ *  assumes the cue sheet corresponds to a CD; the result is undefined
+ *  if the cuesheet's is_cd bit is not set.
+ *
+ * \param object     A pointer to an existing CUESHEET object.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ * \retval FLAC__uint32
+ *    The unsigned integer representation of the CDDB/freedb ID
+ */
+FLAC_API FLAC__uint32 FLAC__metadata_object_cuesheet_calculate_cddb_id(const FLAC__StreamMetadata *object);
+
+/** Sets the MIME type of a PICTURE block.
+ *
+ *  If \a copy is \c true, a copy of the string is stored; otherwise, the object
+ *  takes ownership of the pointer.  The existing string will be freed if this
+ *  function is successful, otherwise the original string will remain if \a copy
+ *  is \c true and malloc() fails.
+ *
+ * \note It is safe to pass a const pointer to \a mime_type if \a copy is \c true.
+ *
+ * \param object      A pointer to an existing PICTURE object.
+ * \param mime_type   A pointer to the MIME type string.  The string must be
+ *                    ASCII characters 0x20-0x7e, NUL-terminated.  No validation
+ *                    is done.
+ * \param copy        See above.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_PICTURE \endcode
+ *    \code (mime_type != NULL) \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_picture_set_mime_type(FLAC__StreamMetadata *object, char *mime_type, FLAC__bool copy);
+
+/** Sets the description of a PICTURE block.
+ *
+ *  If \a copy is \c true, a copy of the string is stored; otherwise, the object
+ *  takes ownership of the pointer.  The existing string will be freed if this
+ *  function is successful, otherwise the original string will remain if \a copy
+ *  is \c true and malloc() fails.
+ *
+ * \note It is safe to pass a const pointer to \a description if \a copy is \c true.
+ *
+ * \param object      A pointer to an existing PICTURE object.
+ * \param description A pointer to the description string.  The string must be
+ *                    valid UTF-8, NUL-terminated.  No validation is done.
+ * \param copy        See above.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_PICTURE \endcode
+ *    \code (description != NULL) \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_picture_set_description(FLAC__StreamMetadata *object, FLAC__byte *description, FLAC__bool copy);
+
+/** Sets the picture data of a PICTURE block.
+ *
+ *  If \a copy is \c true, a copy of the data is stored; otherwise, the object
+ *  takes ownership of the pointer.  Also sets the \a data_length field of the
+ *  metadata object to what is passed in as the \a length parameter.  The
+ *  existing data will be freed if this function is successful, otherwise the
+ *  original data and data_length will remain if \a copy is \c true and
+ *  malloc() fails.
+ *
+ * \note It is safe to pass a const pointer to \a data if \a copy is \c true.
+ *
+ * \param object  A pointer to an existing PICTURE 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_PICTURE \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_picture_set_data(FLAC__StreamMetadata *object, FLAC__byte *data, FLAC__uint32 length, FLAC__bool copy);
+
+/** Check a PICTURE block to see if it conforms to the FLAC specification.
+ *  See the format specification for limits on the contents of the
+ *  PICTURE block.
+ *
+ * \param object     A pointer to existing PICTURE block to be checked.
+ * \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_PICTURE \endcode
+ * \retval FLAC__bool
+ *    \c false if PICTURE block is illegal, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_picture_is_legal(const FLAC__StreamMetadata *object, const char **violation);
 
 /* \} */
 
--- a/sys/src/cmd/audio/libFLAC/FLAC/ordinals.h
+++ b/sys/src/cmd/audio/libFLAC/FLAC/ordinals.h
@@ -1,5 +1,6 @@
 /* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2000,2001,2002,2003,2004  Josh Coalson
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2014  Xiph.Org Foundation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -32,14 +33,15 @@
 #ifndef FLAC__ORDINALS_H
 #define FLAC__ORDINALS_H
 
-#if !defined(_MSC_VER) && !defined(Plan9)
-#include <inttypes.h>
-#endif
+#if defined(_MSC_VER) && _MSC_VER < 1600
 
-typedef signed char FLAC__int8;
-typedef unsigned char FLAC__uint8;
+/* Microsoft Visual Studio earlier than the 2010 version did not provide
+ * the 1999 ISO C Standard header file <stdint.h>.
+ */
 
-#if defined _MSC_VER
+typedef __int8 FLAC__int8;
+typedef unsigned __int8 FLAC__uint8;
+
 typedef __int16 FLAC__int16;
 typedef __int32 FLAC__int32;
 typedef __int64 FLAC__int64;
@@ -46,14 +48,16 @@
 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
+
+/* For MSVC 2010 and everything else which provides <stdint.h>. */
+
+#include <stdint.h>
+
+typedef int8_t FLAC__int8;
+typedef uint8_t FLAC__uint8;
+
 typedef int16_t FLAC__int16;
 typedef int32_t FLAC__int32;
 typedef int64_t FLAC__int64;
@@ -60,12 +64,13 @@
 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
--- a/sys/src/cmd/audio/libFLAC/FLAC/seekable_stream_decoder.h
+++ /dev/null
@@ -1,931 +1,0 @@
-/* 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
--- a/sys/src/cmd/audio/libFLAC/FLAC/seekable_stream_encoder.h
+++ /dev/null
@@ -1,992 +1,0 @@
-/* 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
--- a/sys/src/cmd/audio/libFLAC/FLAC/stream_decoder.h
+++ b/sys/src/cmd/audio/libFLAC/FLAC/stream_decoder.h
@@ -1,5 +1,6 @@
 /* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2000,2001,2002,2003,2004  Josh Coalson
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2014  Xiph.Org Foundation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -32,6 +33,7 @@
 #ifndef FLAC__STREAM_DECODER_H
 #define FLAC__STREAM_DECODER_H
 
+#include <stdio.h> /* for FILE */
 #include "export.h"
 #include "format.h"
 
@@ -50,28 +52,22 @@
  *  \link flac_stream_decoder stream decoder \endlink module.
  */
 
-/** \defgroup flac_decoder FLAC/ *_decoder.h: decoder interfaces
+/** \defgroup flac_decoder FLAC/ \*_decoder.h: decoder interfaces
  *  \ingroup flac
  *
  *  \brief
- *  This module describes the three decoder layers provided by libFLAC.
+ *  This module describes the 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.
+ * The stream decoder can be used to decode complete streams either from
+ * the client via callbacks, or directly from a file, depending on how
+ * it is initialized.  When decoding via callbacks, the client provides
+ * callbacks for reading FLAC data and writing decoded samples, and
+ * handling metadata and errors.  If the client also supplies seek-related
+ * callback, the decoder function for sample-accurate seeking within the
+ * FLAC input is also available.  When decoding from a file, the client
+ * needs only supply a filename or open \c FILE* and write/metadata/error
+ * callbacks; the rest of the callbacks are supplied internally.  For more
+ * info see the \link flac_stream_decoder stream decoder \endlink module.
  */
 
 /** \defgroup flac_stream_decoder FLAC/stream_decoder.h: stream decoder interface
@@ -81,14 +77,20 @@
  *  This module contains the functions which implement the stream
  *  decoder.
  *
+ * The stream decoder can decode native FLAC, and optionally Ogg FLAC
+ * (check FLAC_API_SUPPORTS_OGG_FLAC) streams and files.
+ *
  * 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
+ * - The program overrides the default settings using
  *   FLAC__stream_decoder_set_*() functions.
  * - The program initializes the instance to validate the settings and
- *   prepare for decoding using FLAC__stream_decoder_init().
+ *   prepare for decoding using
+ *   - FLAC__stream_decoder_init_stream() or FLAC__stream_decoder_init_FILE()
+ *     or FLAC__stream_decoder_init_file() for native FLAC,
+ *   - FLAC__stream_decoder_init_ogg_stream() or FLAC__stream_decoder_init_ogg_FILE()
+ *     or FLAC__stream_decoder_init_ogg_file() for Ogg FLAC
  * - 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(),
@@ -99,34 +101,26 @@
  *
  * 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:
+ * functions to override the default decoder options, and call
+ * one of the FLAC__stream_decoder_init_*() functions.
  *
- * - 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.
+ * There are three initialization functions for native FLAC, one for
+ * setting up the decoder to decode FLAC data from the client via
+ * callbacks, and two for decoding directly from a FLAC file.
  *
+ * For decoding via callbacks, use FLAC__stream_decoder_init_stream().
+ * You must also supply several callbacks for handling I/O.  Some (like
+ * seeking) are optional, depending on the capabilities of the input.
+ *
+ * For decoding directly from a file, use FLAC__stream_decoder_init_FILE()
+ * or FLAC__stream_decoder_init_file().  Then you must only supply an open
+ * \c FILE* or filename and fewer callbacks; the decoder will handle
+ * the other callbacks internally.
+ *
+ * There are three similarly-named init functions for decoding from Ogg
+ * FLAC streams.  Check \c FLAC_API_SUPPORTS_OGG_FLAC to find out if the
+ * library has been built with Ogg support.
+ *
  * Once the decoder is initialized, your program will call one of several
  * functions to start the decoding process:
  *
@@ -136,12 +130,12 @@
  *   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
+ *   the first audio frame.  The client 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,
+ *   FLAC__STREAM_DECODER_READ_STATUS_ABORT.  The client will get one metadata,
  *   write, or error callback per metadata block, audio frame, or sync error,
  *   respectively.
  *
@@ -151,12 +145,24 @@
  * 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.
+ * Seeking is exposed through the FLAC__stream_decoder_seek_absolute() method.
+ * At any point after the stream decoder has been initialized, the client 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.
  *
+ * If the client cannot seek via the callback interface provided, but still
+ * has another way of seeking, it can flush the decoder using
+ * FLAC__stream_decoder_flush() and start feeding data from the new position
+ * through the read callback.
+ *
+ * The stream decoder also provides MD5 signature checking.  If this is
+ * turned on before initialization, FLAC__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__stream_decoder_reset()) if there is no signature
+ * in the STREAMINFO block or when a seek is attempted.
+ *
  * 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
@@ -163,13 +169,13 @@
  * 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.
+ * FLAC__stream_decoder_set_metadata_respond() ... sequence to exactly specify
+ * which blocks to return.  Remember that metadata blocks can potentially
+ * be big (for example, cover art) 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.
@@ -178,7 +184,7 @@
  * 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
+ * before FLAC__stream_decoder_init_*().  If this is the case they will
  * return \c true, otherwise \c false.
  *
  * \note
@@ -191,7 +197,7 @@
 
 /** State values for a FLAC__StreamDecoder
  *
- *  The decoder's state can be obtained by calling FLAC__stream_decoder_get_state().
+ * The decoder's state can be obtained by calling FLAC__stream_decoder_get_state().
  */
 typedef enum {
 
@@ -202,7 +208,9 @@
 	/**< 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. */
+	/**< 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. */
@@ -210,26 +218,28 @@
 	FLAC__STREAM_DECODER_END_OF_STREAM,
 	/**< The decoder has reached the end of the stream. */
 
+	FLAC__STREAM_DECODER_OGG_ERROR,
+	/**< An error occurred in the underlying Ogg layer.  */
+
+	FLAC__STREAM_DECODER_SEEK_ERROR,
+	/**< An error occurred while seeking.  The decoder must be flushed
+	 * with FLAC__stream_decoder_flush() or reset with
+	 * FLAC__stream_decoder_reset() before decoding can continue.
+	 */
+
 	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.
+	/**< An error occurred allocating memory.  The decoder is in an invalid
+	 * state and can no longer be used.
 	 */
 
-	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. */
+	/**< The decoder is in the uninitialized state; one of the
+	 * FLAC__stream_decoder_init_*() functions must be called before samples
+	 * can be processed.
+	 */
 
 } FLAC__StreamDecoderState;
 
@@ -241,6 +251,44 @@
 extern FLAC_API const char * const FLAC__StreamDecoderStateString[];
 
 
+/** Possible return values for the FLAC__stream_decoder_init_*() functions.
+ */
+typedef enum {
+
+	FLAC__STREAM_DECODER_INIT_STATUS_OK = 0,
+	/**< Initialization was successful. */
+
+	FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER,
+	/**< The library was not compiled with support for the given container
+	 * format.
+	 */
+
+	FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS,
+	/**< A required callback was not supplied. */
+
+	FLAC__STREAM_DECODER_INIT_STATUS_MEMORY_ALLOCATION_ERROR,
+	/**< An error occurred allocating memory. */
+
+	FLAC__STREAM_DECODER_INIT_STATUS_ERROR_OPENING_FILE,
+	/**< fopen() failed in FLAC__stream_decoder_init_file() or
+	 * FLAC__stream_decoder_init_ogg_file(). */
+
+	FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED
+	/**< FLAC__stream_decoder_init_*() was called when the decoder was
+	 * already initialized, usually because
+	 * FLAC__stream_decoder_finish() was not called.
+	 */
+
+} FLAC__StreamDecoderInitStatus;
+
+/** Maps a FLAC__StreamDecoderInitStatus to a C string.
+ *
+ *  Using a FLAC__StreamDecoderInitStatus as the index to this array
+ *  will give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamDecoderInitStatusString[];
+
+
 /** Return values for the FLAC__StreamDecoder read callback.
  */
 typedef enum {
@@ -249,7 +297,15 @@
 	/**< 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. */
+	/**< The read was attempted while at the end of the stream.  Note that
+	 * the client must only return this value when the read callback was
+	 * called when already at the end of the stream.  Otherwise, if the read
+	 * itself moves to the end of the stream, the client should still return
+	 * the data and \c FLAC__STREAM_DECODER_READ_STATUS_CONTINUE, and then on
+	 * the next read callback it should return
+	 * \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM with a byte count
+	 * of \c 0.
+	 */
 
 	FLAC__STREAM_DECODER_READ_STATUS_ABORT
 	/**< An unrecoverable error occurred.  The decoder will return from the process call. */
@@ -264,6 +320,75 @@
 extern FLAC_API const char * const FLAC__StreamDecoderReadStatusString[];
 
 
+/** Return values for the FLAC__StreamDecoder seek callback.
+ */
+typedef enum {
+
+	FLAC__STREAM_DECODER_SEEK_STATUS_OK,
+	/**< The seek was OK and decoding can continue. */
+
+	FLAC__STREAM_DECODER_SEEK_STATUS_ERROR,
+	/**< An unrecoverable error occurred.  The decoder will return from the process call. */
+
+	FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED
+	/**< Client does not support seeking. */
+
+} FLAC__StreamDecoderSeekStatus;
+
+/** Maps a FLAC__StreamDecoderSeekStatus to a C string.
+ *
+ *  Using a FLAC__StreamDecoderSeekStatus as the index to this array
+ *  will give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamDecoderSeekStatusString[];
+
+
+/** Return values for the FLAC__StreamDecoder tell callback.
+ */
+typedef enum {
+
+	FLAC__STREAM_DECODER_TELL_STATUS_OK,
+	/**< The tell was OK and decoding can continue. */
+
+	FLAC__STREAM_DECODER_TELL_STATUS_ERROR,
+	/**< An unrecoverable error occurred.  The decoder will return from the process call. */
+
+	FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED
+	/**< Client does not support telling the position. */
+
+} FLAC__StreamDecoderTellStatus;
+
+/** Maps a FLAC__StreamDecoderTellStatus to a C string.
+ *
+ *  Using a FLAC__StreamDecoderTellStatus as the index to this array
+ *  will give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamDecoderTellStatusString[];
+
+
+/** Return values for the FLAC__StreamDecoder length callback.
+ */
+typedef enum {
+
+	FLAC__STREAM_DECODER_LENGTH_STATUS_OK,
+	/**< The length call was OK and decoding can continue. */
+
+	FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR,
+	/**< An unrecoverable error occurred.  The decoder will return from the process call. */
+
+	FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED
+	/**< Client does not support reporting the length. */
+
+} FLAC__StreamDecoderLengthStatus;
+
+/** Maps a FLAC__StreamDecoderLengthStatus to a C string.
+ *
+ *  Using a FLAC__StreamDecoderLengthStatus as the index to this array
+ *  will give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamDecoderLengthStatusString[];
+
+
 /** Return values for the FLAC__StreamDecoder write callback.
  */
 typedef enum {
@@ -284,7 +409,20 @@
 extern FLAC_API const char * const FLAC__StreamDecoderWriteStatusString[];
 
 
-/** Possible values passed in to the FLAC__StreamDecoder error callback.
+/** Possible values passed back to the FLAC__StreamDecoder error callback.
+ *  \c FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC is the generic catch-
+ *  all.  The rest could be caused by bad sync (false synchronization on
+ *  data that is not the start of a frame) or corrupted data.  The error
+ *  itself is the decoder's best guess at what happened assuming a correct
+ *  sync.  For example \c FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER
+ *  could be caused by a correct sync on the start of a frame, but some
+ *  data in the frame header was corrupted.  Or it could be the result of
+ *  syncing on a point the stream that looked like the starting of a frame
+ *  but was not.  \c FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM
+ *  could be because the decoder encountered a valid frame made by a future
+ *  version of the encoder which it cannot parse, or because of a false
+ *  sync making it appear as though an encountered frame was generated by
+ *  a future encoder.
  */
 typedef enum {
 
@@ -294,9 +432,12 @@
 	FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER,
 	/**< The decoder encountered a corrupted frame header. */
 
-	FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH
+	FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH,
 	/**< The frame's data did not match the CRC in the footer. */
 
+	FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM
+	/**< The decoder encountered reserved fields in use in the stream. */
+
 } FLAC__StreamDecoderErrorStatus;
 
 /** Maps a FLAC__StreamDecoderErrorStatus to a C string.
@@ -325,8 +466,38 @@
 } FLAC__StreamDecoder;
 
 /** Signature for the read callback.
- *  See FLAC__stream_decoder_set_read_callback() for more info.
  *
+ *  A function pointer matching this signature must be passed to
+ *  FLAC__stream_decoder_init*_stream(). 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.
+ *
+ * Here is an example of a read callback for stdio streams:
+ * \code
+ * FLAC__StreamDecoderReadStatus read_cb(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
+ * {
+ *   FILE *file = ((MyClientData*)client_data)->file;
+ *   if(*bytes > 0) {
+ *     *bytes = fread(buffer, sizeof(FLAC__byte), *bytes, file);
+ *     if(ferror(file))
+ *       return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+ *     else if(*bytes == 0)
+ *       return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+ *     else
+ *       return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+ *   }
+ *   else
+ *     return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+ * }
+ * \endcode
+ *
+ * \note In general, FLAC__StreamDecoder functions which change the
+ * state should not be called on the \a decoder while in the callback.
+ *
  * \param  decoder  The decoder instance calling the callback.
  * \param  buffer   A pointer to a location for the callee to store
  *                  data to be decoded.
@@ -337,15 +508,164 @@
  *                  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().
+ *                      FLAC__stream_decoder_init_*().
  * \retval FLAC__StreamDecoderReadStatus
+ *    The callee's return status.  Note that the callback should return
+ *    \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM if and only if
+ *    zero bytes were read and there is no more data to be read.
+ */
+typedef FLAC__StreamDecoderReadStatus (*FLAC__StreamDecoderReadCallback)(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data);
+
+/** Signature for the seek callback.
+ *
+ *  A function pointer matching this signature may be passed to
+ *  FLAC__stream_decoder_init*_stream().  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.
+ *
+ * Here is an example of a seek callback for stdio streams:
+ * \code
+ * FLAC__StreamDecoderSeekStatus seek_cb(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data)
+ * {
+ *   FILE *file = ((MyClientData*)client_data)->file;
+ *   if(file == stdin)
+ *     return FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED;
+ *   else if(fseeko(file, (off_t)absolute_byte_offset, SEEK_SET) < 0)
+ *     return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
+ *   else
+ *     return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
+ * }
+ * \endcode
+ *
+ * \note In general, FLAC__StreamDecoder functions which change the
+ * state should not be called on the \a decoder while in the callback.
+ *
+ * \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__stream_decoder_init_*().
+ * \retval FLAC__StreamDecoderSeekStatus
  *    The callee's return status.
  */
-typedef FLAC__StreamDecoderReadStatus (*FLAC__StreamDecoderReadCallback)(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data);
+typedef FLAC__StreamDecoderSeekStatus (*FLAC__StreamDecoderSeekCallback)(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data);
 
+/** Signature for the tell callback.
+ *
+ *  A function pointer matching this signature may be passed to
+ *  FLAC__stream_decoder_init*_stream().  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.
+ *
+ * Here is an example of a tell callback for stdio streams:
+ * \code
+ * FLAC__StreamDecoderTellStatus tell_cb(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
+ * {
+ *   FILE *file = ((MyClientData*)client_data)->file;
+ *   off_t pos;
+ *   if(file == stdin)
+ *     return FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED;
+ *   else if((pos = ftello(file)) < 0)
+ *     return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
+ *   else {
+ *     *absolute_byte_offset = (FLAC__uint64)pos;
+ *     return FLAC__STREAM_DECODER_TELL_STATUS_OK;
+ *   }
+ * }
+ * \endcode
+ *
+ * \note In general, FLAC__StreamDecoder functions which change the
+ * state should not be called on the \a decoder while in the callback.
+ *
+ * \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__stream_decoder_init_*().
+ * \retval FLAC__StreamDecoderTellStatus
+ *    The callee's return status.
+ */
+typedef FLAC__StreamDecoderTellStatus (*FLAC__StreamDecoderTellCallback)(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data);
+
+/** Signature for the length callback.
+ *
+ *  A function pointer matching this signature may be passed to
+ *  FLAC__stream_decoder_init*_stream().  The supplied function will be
+ *  called when the decoder wants to know the total length of the stream
+ *  in bytes.
+ *
+ * Here is an example of a length callback for stdio streams:
+ * \code
+ * FLAC__StreamDecoderLengthStatus length_cb(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data)
+ * {
+ *   FILE *file = ((MyClientData*)client_data)->file;
+ *   struct stat filestats;
+ *
+ *   if(file == stdin)
+ *     return FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED;
+ *   else if(fstat(fileno(file), &filestats) != 0)
+ *     return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
+ *   else {
+ *     *stream_length = (FLAC__uint64)filestats.st_size;
+ *     return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
+ *   }
+ * }
+ * \endcode
+ *
+ * \note In general, FLAC__StreamDecoder functions which change the
+ * state should not be called on the \a decoder while in the callback.
+ *
+ * \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__stream_decoder_init_*().
+ * \retval FLAC__StreamDecoderLengthStatus
+ *    The callee's return status.
+ */
+typedef FLAC__StreamDecoderLengthStatus (*FLAC__StreamDecoderLengthCallback)(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data);
+
+/** Signature for the EOF callback.
+ *
+ *  A function pointer matching this signature may be passed to
+ *  FLAC__stream_decoder_init*_stream().  The supplied function will be
+ *  called when the decoder needs to know if the end of the stream has
+ *  been reached.
+ *
+ * Here is an example of a EOF callback for stdio streams:
+ * FLAC__bool eof_cb(const FLAC__StreamDecoder *decoder, void *client_data)
+ * \code
+ * {
+ *   FILE *file = ((MyClientData*)client_data)->file;
+ *   return feof(file)? true : false;
+ * }
+ * \endcode
+ *
+ * \note In general, FLAC__StreamDecoder functions which change the
+ * state should not be called on the \a decoder while in the callback.
+ *
+ * \param  decoder  The decoder instance calling the callback.
+ * \param  client_data  The callee's client data set through
+ *                      FLAC__stream_decoder_init_*().
+ * \retval FLAC__bool
+ *    \c true if the currently at the end of the stream, else \c false.
+ */
+typedef FLAC__bool (*FLAC__StreamDecoderEofCallback)(const FLAC__StreamDecoder *decoder, void *client_data);
+
 /** Signature for the write callback.
- *  See FLAC__stream_decoder_set_write_callback() for more info.
  *
+ *  A function pointer matching this signature must be passed to one of
+ *  the FLAC__stream_decoder_init_*() functions.
+ *  The supplied function will be called when the decoder has decoded a
+ *  single audio frame.  The decoder will pass the frame metadata as well
+ *  as an array of pointers (one for each channel) pointing to the
+ *  decoded audio.
+ *
+ * \note In general, FLAC__StreamDecoder functions which change the
+ * state should not be called on the \a decoder while in the callback.
+ *
  * \param  decoder  The decoder instance calling the callback.
  * \param  frame    The description of the decoded frame.  See
  *                  FLAC__Frame.
@@ -352,11 +672,11 @@
  * \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.
+ *                  Channels will be ordered according to the FLAC
+ *                  specification; see the documentation for the
+ *                  <A HREF="../format.html#frame_header">frame header</A>.
  * \param  client_data  The callee's client data set through
- *                      FLAC__stream_decoder_set_client_data().
+ *                      FLAC__stream_decoder_init_*().
  * \retval FLAC__StreamDecoderWriteStatus
  *    The callee's return status.
  */
@@ -363,22 +683,46 @@
 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.
  *
+ *  A function pointer matching this signature must be passed to one of
+ *  the FLAC__stream_decoder_init_*() functions.
+ *  The supplied function will be called when the decoder has decoded a
+ *  metadata block.  In a valid FLAC file there will always be one
+ *  \c 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
+ *  \c STREAMINFO block; you can instruct the decoder to pass or filter
+ *  other blocks with FLAC__stream_decoder_set_metadata_*() calls.
+ *
+ * \note In general, FLAC__StreamDecoder functions which change the
+ * state should not be called on the \a decoder while in the callback.
+ *
  * \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().
+ *                      FLAC__stream_decoder_init_*().
  */
 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.
  *
+ *  A function pointer matching this signature must be passed to one of
+ *  the FLAC__stream_decoder_init_*() functions.
+ *  The supplied function will be called whenever an error occurs during
+ *  decoding.
+ *
+ * \note In general, FLAC__StreamDecoder functions which change the
+ * state should not be called on the \a decoder while in the callback.
+ *
  * \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().
+ *                      FLAC__stream_decoder_init_*().
  */
 typedef void (*FLAC__StreamDecoderErrorCallback)(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
 
@@ -413,108 +757,46 @@
  *
  ***********************************************************************/
 
-/** 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.
+/** Set the serial number for the FLAC stream within the Ogg container.
+ *  The default behavior is to use the serial number of the first Ogg
+ *  page.  Setting a serial number here will explicitly specify which
+ *  stream is to be decoded.
  *
  * \note
- * The callback is mandatory and must be set before initialization.
+ * This does not need to be set for native FLAC decoding.
  *
- * \default \c NULL
- * \param  decoder  A decoder instance to set.
- * \param  value    See above.
+ * \default \c use serial number of first page
+ * \param  decoder        A decoder instance to set.
+ * \param  serial_number  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);
+FLAC_API FLAC__bool FLAC__stream_decoder_set_ogg_serial_number(FLAC__StreamDecoder *decoder, long serial_number);
 
-/** 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.
+/** 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__stream_decoder_finish().
  *
- * \note
- * The callback is mandatory and must be set before initialization.
+ *  MD5 signature checking will be turned off (until the next
+ *  FLAC__stream_decoder_reset()) if there is no signature in the
+ *  STREAMINFO block or when a seek is attempted.
  *
- * \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.
+ *  Clients that do not use the MD5 check should leave this off to speed
+ *  up decoding.
  *
- * \note
- * The callback is mandatory and must be set before initialization.
- *
- * \default \c NULL
+ * \default \c false
  * \param  decoder  A decoder instance to set.
- * \param  value    See above.
+ * \param  value    Flag 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);
+FLAC_API FLAC__bool FLAC__stream_decoder_set_md5_checking(FLAC__StreamDecoder *decoder, FLAC__bool 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
@@ -617,6 +899,32 @@
  */
 FLAC_API const char *FLAC__stream_decoder_get_resolved_state_string(const FLAC__StreamDecoder *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__stream_decoder_get_md5_checking(const FLAC__StreamDecoder *decoder);
+
+/** Get the total number of samples in the stream being decoded.
+ *  Will only be valid after decoding has started and will contain the
+ *  value from the \c STREAMINFO block.  A value of \c 0 means "unknown".
+ *
+ * \param  decoder  A decoder instance to query.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval unsigned
+ *    See above.
+ */
+FLAC_API FLAC__uint64 FLAC__stream_decoder_get_total_samples(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.
@@ -677,23 +985,369 @@
  */
 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
+/** 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.
+ *
+ *  \warning This function currently only works for native FLAC,
+ *           not Ogg FLAC streams.
+ *
+ * \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 the stream is not native FLAC,
+ *    or there was an error from the 'tell' callback or it returned
+ *    \c FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_get_decode_position(const FLAC__StreamDecoder *decoder, FLAC__uint64 *position);
+
+/** Initialize the decoder instance to decode native FLAC streams.
+ *
+ *  This flavor of initialization sets up the decoder to decode from a
+ *  native FLAC stream. I/O is performed via callbacks to the client.
+ *  For decoding from a plain file via filename or open FILE*,
+ *  FLAC__stream_decoder_init_file() and FLAC__stream_decoder_init_FILE()
+ *  provide a simpler interface.
+ *
+ *  This function 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.
+ * \param  decoder            An uninitialized decoder instance.
+ * \param  read_callback      See FLAC__StreamDecoderReadCallback.  This
+ *                            pointer must not be \c NULL.
+ * \param  seek_callback      See FLAC__StreamDecoderSeekCallback.  This
+ *                            pointer may be \c NULL if seeking is not
+ *                            supported.  If \a seek_callback is not \c NULL then a
+ *                            \a tell_callback, \a length_callback, and \a eof_callback must also be supplied.
+ *                            Alternatively, a dummy seek callback that just
+ *                            returns \c FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED
+ *                            may also be supplied, all though this is slightly
+ *                            less efficient for the decoder.
+ * \param  tell_callback      See FLAC__StreamDecoderTellCallback.  This
+ *                            pointer may be \c NULL if not supported by the client.  If
+ *                            \a seek_callback is not \c NULL then a
+ *                            \a tell_callback must also be supplied.
+ *                            Alternatively, a dummy tell callback that just
+ *                            returns \c FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED
+ *                            may also be supplied, all though this is slightly
+ *                            less efficient for the decoder.
+ * \param  length_callback    See FLAC__StreamDecoderLengthCallback.  This
+ *                            pointer may be \c NULL if not supported by the client.  If
+ *                            \a seek_callback is not \c NULL then a
+ *                            \a length_callback must also be supplied.
+ *                            Alternatively, a dummy length callback that just
+ *                            returns \c FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED
+ *                            may also be supplied, all though this is slightly
+ *                            less efficient for the decoder.
+ * \param  eof_callback       See FLAC__StreamDecoderEofCallback.  This
+ *                            pointer may be \c NULL if not supported by the client.  If
+ *                            \a seek_callback is not \c NULL then a
+ *                            \a eof_callback must also be supplied.
+ *                            Alternatively, a dummy length callback that just
+ *                            returns \c false
+ *                            may also be supplied, all though this is slightly
+ *                            less efficient for the decoder.
+ * \param  write_callback     See FLAC__StreamDecoderWriteCallback.  This
+ *                            pointer must not be \c NULL.
+ * \param  metadata_callback  See FLAC__StreamDecoderMetadataCallback.  This
+ *                            pointer may be \c NULL if the callback is not
+ *                            desired.
+ * \param  error_callback     See FLAC__StreamDecoderErrorCallback.  This
+ *                            pointer must not be \c NULL.
+ * \param  client_data        This value will be supplied to callbacks in their
+ *                            \a client_data argument.
  * \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.
+ * \retval FLAC__StreamDecoderInitStatus
+ *    \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful;
+ *    see FLAC__StreamDecoderInitStatus for the meanings of other return values.
  */
-FLAC_API FLAC__StreamDecoderState FLAC__stream_decoder_init(FLAC__StreamDecoder *decoder);
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_stream(
+	FLAC__StreamDecoder *decoder,
+	FLAC__StreamDecoderReadCallback read_callback,
+	FLAC__StreamDecoderSeekCallback seek_callback,
+	FLAC__StreamDecoderTellCallback tell_callback,
+	FLAC__StreamDecoderLengthCallback length_callback,
+	FLAC__StreamDecoderEofCallback eof_callback,
+	FLAC__StreamDecoderWriteCallback write_callback,
+	FLAC__StreamDecoderMetadataCallback metadata_callback,
+	FLAC__StreamDecoderErrorCallback error_callback,
+	void *client_data
+);
 
+/** Initialize the decoder instance to decode Ogg FLAC streams.
+ *
+ *  This flavor of initialization sets up the decoder to decode from a
+ *  FLAC stream in an Ogg container. I/O is performed via callbacks to the
+ *  client.  For decoding from a plain file via filename or open FILE*,
+ *  FLAC__stream_decoder_init_ogg_file() and FLAC__stream_decoder_init_ogg_FILE()
+ *  provide a simpler interface.
+ *
+ *  This function 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.
+ *
+ *  \note Support for Ogg FLAC in the library is optional.  If this
+ *  library has been built without support for Ogg FLAC, this function
+ *  will return \c FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER.
+ *
+ * \param  decoder            An uninitialized decoder instance.
+ * \param  read_callback      See FLAC__StreamDecoderReadCallback.  This
+ *                            pointer must not be \c NULL.
+ * \param  seek_callback      See FLAC__StreamDecoderSeekCallback.  This
+ *                            pointer may be \c NULL if seeking is not
+ *                            supported.  If \a seek_callback is not \c NULL then a
+ *                            \a tell_callback, \a length_callback, and \a eof_callback must also be supplied.
+ *                            Alternatively, a dummy seek callback that just
+ *                            returns \c FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED
+ *                            may also be supplied, all though this is slightly
+ *                            less efficient for the decoder.
+ * \param  tell_callback      See FLAC__StreamDecoderTellCallback.  This
+ *                            pointer may be \c NULL if not supported by the client.  If
+ *                            \a seek_callback is not \c NULL then a
+ *                            \a tell_callback must also be supplied.
+ *                            Alternatively, a dummy tell callback that just
+ *                            returns \c FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED
+ *                            may also be supplied, all though this is slightly
+ *                            less efficient for the decoder.
+ * \param  length_callback    See FLAC__StreamDecoderLengthCallback.  This
+ *                            pointer may be \c NULL if not supported by the client.  If
+ *                            \a seek_callback is not \c NULL then a
+ *                            \a length_callback must also be supplied.
+ *                            Alternatively, a dummy length callback that just
+ *                            returns \c FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED
+ *                            may also be supplied, all though this is slightly
+ *                            less efficient for the decoder.
+ * \param  eof_callback       See FLAC__StreamDecoderEofCallback.  This
+ *                            pointer may be \c NULL if not supported by the client.  If
+ *                            \a seek_callback is not \c NULL then a
+ *                            \a eof_callback must also be supplied.
+ *                            Alternatively, a dummy length callback that just
+ *                            returns \c false
+ *                            may also be supplied, all though this is slightly
+ *                            less efficient for the decoder.
+ * \param  write_callback     See FLAC__StreamDecoderWriteCallback.  This
+ *                            pointer must not be \c NULL.
+ * \param  metadata_callback  See FLAC__StreamDecoderMetadataCallback.  This
+ *                            pointer may be \c NULL if the callback is not
+ *                            desired.
+ * \param  error_callback     See FLAC__StreamDecoderErrorCallback.  This
+ *                            pointer must not be \c NULL.
+ * \param  client_data        This value will be supplied to callbacks in their
+ *                            \a client_data argument.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__StreamDecoderInitStatus
+ *    \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful;
+ *    see FLAC__StreamDecoderInitStatus for the meanings of other return values.
+ */
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_stream(
+	FLAC__StreamDecoder *decoder,
+	FLAC__StreamDecoderReadCallback read_callback,
+	FLAC__StreamDecoderSeekCallback seek_callback,
+	FLAC__StreamDecoderTellCallback tell_callback,
+	FLAC__StreamDecoderLengthCallback length_callback,
+	FLAC__StreamDecoderEofCallback eof_callback,
+	FLAC__StreamDecoderWriteCallback write_callback,
+	FLAC__StreamDecoderMetadataCallback metadata_callback,
+	FLAC__StreamDecoderErrorCallback error_callback,
+	void *client_data
+);
+
+/** Initialize the decoder instance to decode native FLAC files.
+ *
+ *  This flavor of initialization sets up the decoder to decode from a
+ *  plain native FLAC file.  For non-stdio streams, you must use
+ *  FLAC__stream_decoder_init_stream() and provide callbacks for the I/O.
+ *
+ *  This function 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.
+ * \param  file               An open FLAC file.  The file should have been
+ *                            opened with mode \c "rb" and rewound.  The file
+ *                            becomes owned by the decoder and should not be
+ *                            manipulated by the client while decoding.
+ *                            Unless \a file is \c stdin, it will be closed
+ *                            when FLAC__stream_decoder_finish() is called.
+ *                            Note however that seeking will not work when
+ *                            decoding from \c stdout since it is not seekable.
+ * \param  write_callback     See FLAC__StreamDecoderWriteCallback.  This
+ *                            pointer must not be \c NULL.
+ * \param  metadata_callback  See FLAC__StreamDecoderMetadataCallback.  This
+ *                            pointer may be \c NULL if the callback is not
+ *                            desired.
+ * \param  error_callback     See FLAC__StreamDecoderErrorCallback.  This
+ *                            pointer must not be \c NULL.
+ * \param  client_data        This value will be supplied to callbacks in their
+ *                            \a client_data argument.
+ * \assert
+ *    \code decoder != NULL \endcode
+ *    \code file != NULL \endcode
+ * \retval FLAC__StreamDecoderInitStatus
+ *    \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful;
+ *    see FLAC__StreamDecoderInitStatus for the meanings of other return values.
+ */
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_FILE(
+	FLAC__StreamDecoder *decoder,
+	FILE *file,
+	FLAC__StreamDecoderWriteCallback write_callback,
+	FLAC__StreamDecoderMetadataCallback metadata_callback,
+	FLAC__StreamDecoderErrorCallback error_callback,
+	void *client_data
+);
+
+/** Initialize the decoder instance to decode Ogg FLAC files.
+ *
+ *  This flavor of initialization sets up the decoder to decode from a
+ *  plain Ogg FLAC file.  For non-stdio streams, you must use
+ *  FLAC__stream_decoder_init_ogg_stream() and provide callbacks for the I/O.
+ *
+ *  This function 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.
+ *
+ *  \note Support for Ogg FLAC in the library is optional.  If this
+ *  library has been built without support for Ogg FLAC, this function
+ *  will return \c FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER.
+ *
+ * \param  decoder            An uninitialized decoder instance.
+ * \param  file               An open FLAC file.  The file should have been
+ *                            opened with mode \c "rb" and rewound.  The file
+ *                            becomes owned by the decoder and should not be
+ *                            manipulated by the client while decoding.
+ *                            Unless \a file is \c stdin, it will be closed
+ *                            when FLAC__stream_decoder_finish() is called.
+ *                            Note however that seeking will not work when
+ *                            decoding from \c stdout since it is not seekable.
+ * \param  write_callback     See FLAC__StreamDecoderWriteCallback.  This
+ *                            pointer must not be \c NULL.
+ * \param  metadata_callback  See FLAC__StreamDecoderMetadataCallback.  This
+ *                            pointer may be \c NULL if the callback is not
+ *                            desired.
+ * \param  error_callback     See FLAC__StreamDecoderErrorCallback.  This
+ *                            pointer must not be \c NULL.
+ * \param  client_data        This value will be supplied to callbacks in their
+ *                            \a client_data argument.
+ * \assert
+ *    \code decoder != NULL \endcode
+ *    \code file != NULL \endcode
+ * \retval FLAC__StreamDecoderInitStatus
+ *    \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful;
+ *    see FLAC__StreamDecoderInitStatus for the meanings of other return values.
+ */
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_FILE(
+	FLAC__StreamDecoder *decoder,
+	FILE *file,
+	FLAC__StreamDecoderWriteCallback write_callback,
+	FLAC__StreamDecoderMetadataCallback metadata_callback,
+	FLAC__StreamDecoderErrorCallback error_callback,
+	void *client_data
+);
+
+/** Initialize the decoder instance to decode native FLAC files.
+ *
+ *  This flavor of initialization sets up the decoder to decode from a plain
+ *  native FLAC file.  If POSIX fopen() semantics are not sufficient, (for
+ *  example, with Unicode filenames on Windows), you must use
+ *  FLAC__stream_decoder_init_FILE(), or FLAC__stream_decoder_init_stream()
+ *  and provide callbacks for the I/O.
+ *
+ *  This function 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.
+ * \param  filename           The name of the file to decode from.  The file will
+ *                            be opened with fopen().  Use \c NULL to decode from
+ *                            \c stdin.  Note that \c stdin is not seekable.
+ * \param  write_callback     See FLAC__StreamDecoderWriteCallback.  This
+ *                            pointer must not be \c NULL.
+ * \param  metadata_callback  See FLAC__StreamDecoderMetadataCallback.  This
+ *                            pointer may be \c NULL if the callback is not
+ *                            desired.
+ * \param  error_callback     See FLAC__StreamDecoderErrorCallback.  This
+ *                            pointer must not be \c NULL.
+ * \param  client_data        This value will be supplied to callbacks in their
+ *                            \a client_data argument.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__StreamDecoderInitStatus
+ *    \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful;
+ *    see FLAC__StreamDecoderInitStatus for the meanings of other return values.
+ */
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_file(
+	FLAC__StreamDecoder *decoder,
+	const char *filename,
+	FLAC__StreamDecoderWriteCallback write_callback,
+	FLAC__StreamDecoderMetadataCallback metadata_callback,
+	FLAC__StreamDecoderErrorCallback error_callback,
+	void *client_data
+);
+
+/** Initialize the decoder instance to decode Ogg FLAC files.
+ *
+ *  This flavor of initialization sets up the decoder to decode from a plain
+ *  Ogg FLAC file.  If POSIX fopen() semantics are not sufficient, (for
+ *  example, with Unicode filenames on Windows), you must use
+ *  FLAC__stream_decoder_init_ogg_FILE(), or FLAC__stream_decoder_init_ogg_stream()
+ *  and provide callbacks for the I/O.
+ *
+ *  This function 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.
+ *
+ *  \note Support for Ogg FLAC in the library is optional.  If this
+ *  library has been built without support for Ogg FLAC, this function
+ *  will return \c FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER.
+ *
+ * \param  decoder            An uninitialized decoder instance.
+ * \param  filename           The name of the file to decode from.  The file will
+ *                            be opened with fopen().  Use \c NULL to decode from
+ *                            \c stdin.  Note that \c stdin is not seekable.
+ * \param  write_callback     See FLAC__StreamDecoderWriteCallback.  This
+ *                            pointer must not be \c NULL.
+ * \param  metadata_callback  See FLAC__StreamDecoderMetadataCallback.  This
+ *                            pointer may be \c NULL if the callback is not
+ *                            desired.
+ * \param  error_callback     See FLAC__StreamDecoderErrorCallback.  This
+ *                            pointer must not be \c NULL.
+ * \param  client_data        This value will be supplied to callbacks in their
+ *                            \a client_data argument.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__StreamDecoderInitStatus
+ *    \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful;
+ *    see FLAC__StreamDecoderInitStatus for the meanings of other return values.
+ */
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_file(
+	FLAC__StreamDecoder *decoder,
+	const char *filename,
+	FLAC__StreamDecoderWriteCallback write_callback,
+	FLAC__StreamDecoderMetadataCallback metadata_callback,
+	FLAC__StreamDecoderErrorCallback error_callback,
+	void *client_data
+);
+
 /** Finish the decoding process.
  *  Flushes the decoding buffer, releases resources, resets the decoder
  *  settings to their defaults, and returns the decoder state to
@@ -701,18 +1355,24 @@
  *
  *  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()
+ *  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
+ * \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 void FLAC__stream_decoder_finish(FLAC__StreamDecoder *decoder);
+FLAC_API FLAC__bool 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.
+ *  \c FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC.  This will also turn
+ *  off MD5 checking.
  *
  * \param  decoder  A decoder instance.
  * \assert
@@ -719,7 +1379,8 @@
  *    \code decoder != NULL \endcode
  * \retval FLAC__bool
  *    \c true if successful, else \c false if a memory allocation
- *    error occurs.
+ *    error occurs (in which case the state will be set to
+ *    \c FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR).
  */
 FLAC_API FLAC__bool FLAC__stream_decoder_flush(FLAC__StreamDecoder *decoder);
 
@@ -727,15 +1388,32 @@
  *  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.
+ *  preserved; there is no need to call FLAC__stream_decoder_init_*()
+ *  before decoding again.  MD5 checking will be restored to its original
+ *  setting.
  *
+ *  If the decoder is seekable, or was initialized with
+ *  FLAC__stream_decoder_init*_FILE() or FLAC__stream_decoder_init*_file(),
+ *  the decoder will also attempt to seek to the beginning of the file.
+ *  If this rewind fails, this function will return \c false.  It follows
+ *  that FLAC__stream_decoder_reset() cannot be used when decoding from
+ *  \c stdin.
+ *
+ *  If the decoder was initialized with FLAC__stream_encoder_init*_stream()
+ *  and is not seekable (i.e. no seek callback was provided or the seek
+ *  callback returns \c FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED), it
+ *  is the duty of the client to start feeding data from the beginning of
+ *  the stream on the next FLAC__stream_decoder_process() or
+ *  FLAC__stream_decoder_process_interleaved() call.
+ *
  * \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.
+ *    \c true if successful, else \c false if a memory allocation occurs
+ *    (in which case the state will be set to
+ *    \c FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR) or a seek error
+ *    occurs (the state will be unchanged).
  */
 FLAC_API FLAC__bool FLAC__stream_decoder_reset(FLAC__StreamDecoder *decoder);
 
@@ -747,9 +1425,7 @@
  *
  *  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.
+ *  called with the decoded metadata block or audio frame.
  *
  *  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
@@ -756,7 +1432,7 @@
  *  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
+ *  a 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
@@ -767,11 +1443,10 @@
  * \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).
+ *    \c false if any fatal read, write, or memory allocation error
+ *    occurred (meaning decoding must stop), else \c true; for more
+ *    information about the decoder, check the decoder state with
+ *    FLAC__stream_decoder_get_state().
  */
 FLAC_API FLAC__bool FLAC__stream_decoder_process_single(FLAC__StreamDecoder *decoder);
 
@@ -783,18 +1458,16 @@
  *
  *  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.
+ *  with the decoded metadata.
  *
  * \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).
+ *    \c false if any fatal read, write, or memory allocation error
+ *    occurred (meaning decoding must stop), else \c true; for more
+ *    information about the decoder, check the decoder state with
+ *    FLAC__stream_decoder_get_state().
  */
 FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_metadata(FLAC__StreamDecoder *decoder);
 
@@ -806,18 +1479,16 @@
  *
  *  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.
+ *  callback will be called with the decoded metadata or frame.
  *
  * \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).
+ *    \c false if any fatal read, write, or memory allocation error
+ *    occurred (meaning decoding must stop), else \c true; for more
+ *    information about the decoder, check the decoder state with
+ *    FLAC__stream_decoder_get_state().
  */
 FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_stream(FLAC__StreamDecoder *decoder);
 
@@ -836,15 +1507,14 @@
  *  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
+ *  This function can be used in more quickly determining FLAC frame
+ *  boundaries when decoding of the actual data is not needed, for
+ *  example when an application is separating a FLAC stream into frames
+ *  for editing or storing in a container.  To do this, the application
+ *  can use FLAC__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.
+ *  FLAC__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.
@@ -854,15 +1524,32 @@
  * \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
+ *    \c false if any fatal read, write, or memory allocation error
+ *    occurred (meaning decoding must stop), 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__STREAM_DECODER_READ_METADATA state, else \c true; for more
+ *    information about the decoder, check the decoder state with
+ *    FLAC__stream_decoder_get_state().
  */
 FLAC_API FLAC__bool FLAC__stream_decoder_skip_single_frame(FLAC__StreamDecoder *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.  The
+ *  client must support seeking the input or this function will fail
+ *  and return \c false.  Furthermore, if the decoder state is
+ *  \c FLAC__STREAM_DECODER_SEEK_ERROR, then the decoder must be flushed
+ *  with FLAC__stream_decoder_flush() or reset with
+ *  FLAC__stream_decoder_reset() before decoding can continue.
+ *
+ * \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__stream_decoder_seek_absolute(FLAC__StreamDecoder *decoder, FLAC__uint64 sample);
 
 /* \} */
 
--- a/sys/src/cmd/audio/libFLAC/FLAC/stream_encoder.h
+++ b/sys/src/cmd/audio/libFLAC/FLAC/stream_encoder.h
@@ -1,5 +1,6 @@
 /* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2000,2001,2002,2003,2004  Josh Coalson
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2014  Xiph.Org Foundation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -32,6 +33,7 @@
 #ifndef FLAC__STREAM_ENCODER_H
 #define FLAC__STREAM_ENCODER_H
 
+#include <stdio.h> /* for FILE */
 #include "export.h"
 #include "format.h"
 #include "stream_decoder.h"
@@ -51,33 +53,23 @@
  *  \link flac_stream_encoder stream encoder \endlink module.
  */
 
-/** \defgroup flac_encoder FLAC/ *_encoder.h: encoder interfaces
+/** \defgroup flac_encoder FLAC/ \*_encoder.h: encoder interfaces
  *  \ingroup flac
  *
  *  \brief
- *  This module describes the two encoder layers provided by libFLAC.
+ *  This module describes the 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.
+ * The stream encoder can be used to encode complete streams either to the
+ * client via callbacks, or directly to a file, depending on how it is
+ * initialized.  When encoding via callbacks, the client provides a write
+ * callback which will be called whenever FLAC data is ready to be written.
+ * If the client also supplies a seek callback, the encoder will also
+ * automatically handle the writing back of metadata discovered while
+ * encoding, like stream info, seek points offsets, etc.  When encoding to
+ * a file, the client needs only supply a filename or open \c FILE* and an
+ * optional progress callback for periodic notification of progress; the
+ * write and seek callbacks are supplied internally.  For more info see the
+ * \link flac_stream_encoder stream encoder \endlink module.
  */
 
 /** \defgroup flac_stream_encoder FLAC/stream_encoder.h: stream encoder interface
@@ -87,13 +79,34 @@
  *  This module contains the functions which implement the stream
  *  encoder.
  *
+ * The stream encoder can encode to native FLAC, and optionally Ogg FLAC
+ * (check FLAC_API_SUPPORTS_OGG_FLAC) streams and files.
+ *
  * 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 overrides the default settings using
+ *   FLAC__stream_encoder_set_*() functions.  At a minimum, the following
+ *   functions should be called:
+ *   - FLAC__stream_encoder_set_channels()
+ *   - FLAC__stream_encoder_set_bits_per_sample()
+ *   - FLAC__stream_encoder_set_sample_rate()
+ *   - FLAC__stream_encoder_set_ogg_serial_number() (if encoding to Ogg FLAC)
+ *   - FLAC__stream_encoder_set_total_samples_estimate() (if known)
+ * - If the application wants to control the compression level or set its own
+ *   metadata, then the following should also be called:
+ *   - FLAC__stream_encoder_set_compression_level()
+ *   - FLAC__stream_encoder_set_verify()
+ *   - FLAC__stream_encoder_set_metadata()
+ * - The rest of the set functions should only be called if the client needs
+ *   exact control over how the audio is compressed; thorough understanding
+ *   of the FLAC format is necessary to achieve good results.
  * - The program initializes the instance to validate the settings and
- *   prepare for encoding using FLAC__stream_encoder_init().
+ *   prepare for encoding using
+ *   - FLAC__stream_encoder_init_stream() or FLAC__stream_encoder_init_FILE()
+ *     or FLAC__stream_encoder_init_file() for native FLAC
+ *   - FLAC__stream_encoder_init_ogg_stream() or FLAC__stream_encoder_init_ogg_FILE()
+ *     or FLAC__stream_encoder_init_ogg_file() for Ogg FLAC
  * - 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
@@ -100,56 +113,69 @@
  *   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.
+ *   update the metadata with the final encoding statistics if output
+ *   seeking is possible, 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
+ * callbacks and more options.  Typically the client 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().
+ * parameters with FLAC__stream_encoder_set_*(), and initialize it by
+ * calling one of the FLAC__stream_encoder_init_*() functions.
  *
  * 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>
+ * <A HREF="../documentation_format_overview.html">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.
+ * values as many are interdependent.  The FLAC__stream_encoder_init_*()
+ * functions 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_INIT_STATUS_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:
+ * There are three initialization functions for native FLAC, one for
+ * setting up the encoder to encode FLAC data to the client via
+ * callbacks, and two for encoding directly to a file.
  *
- * - 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).
+ * For encoding via callbacks, use FLAC__stream_encoder_init_stream().
+ * You must also supply a write callback which will be called anytime
+ * there is raw encoded data to write.  If the client can seek the output
+ * it is best to also supply seek and tell callbacks, as this allows the
+ * encoder to go back after encoding is finished to write back
+ * information that was collected while encoding, like seek point offsets,
+ * frame sizes, etc.
  *
- * The call to FLAC__stream_encoder_init() currently will also immediately
+ * For encoding directly to a file, use FLAC__stream_encoder_init_FILE()
+ * or FLAC__stream_encoder_init_file().  Then you must only supply a
+ * filename or open \c FILE*; the encoder will handle all the callbacks
+ * internally.  You may also supply a progress callback for periodic
+ * notification of the encoding progress.
+ *
+ * There are three similarly-named init functions for encoding to Ogg
+ * FLAC streams.  Check \c FLAC_API_SUPPORTS_OGG_FLAC to find out if the
+ * library has been built with Ogg support.
+ *
+ * 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.
+ * and once for each encoded metadata block.  Note that for Ogg FLAC
+ * encoding you will usually get at least twice the number of callbacks than
+ * with native FLAC, one for the Ogg page header and one for the page body.
  *
- * After initializing the instance, the user may feed audio data to the
+ * After initializing the instance, the client may feed audio data to the
  * encoder in one of two ways:
  *
- * - Channel separate, through FLAC__stream_encoder_process() - The user
+ * - Channel separate, through FLAC__stream_encoder_process() - The client
  *   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.
+ *   block-aligned, but each channel should have the same number of samples.
  * - Channel interleaved, through
- *   FLAC__stream_encoder_process_interleaved() - The user will pass a single
+ *   FLAC__stream_encoder_process_interleaved() - The client 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
@@ -156,7 +182,12 @@
  *   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
+ * Note that for either process call, each sample in the buffers should be a
+ * signed integer, right-justified to the resolution set by
+ * FLAC__stream_encoder_set_bits_per_sample().  For example, if the resolution
+ * is 16 bits per sample, the samples should all be in the range [-32768,32767].
+ *
+ * When the client 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
@@ -177,29 +208,50 @@
  * for the specification of metadata blocks and their lengths.
  *
  * \note
+ * If you are writing the FLAC data to a file via callbacks, 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.  (If using FLAC__stream_encoder_init*_file() or
+ * FLAC__stream_encoder_init*_FILE(), the file is managed internally.)
+ *
+ * \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
+ * 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.
+ * defaults.
  *
  * \{
  */
 
 
-/** State values for a FLAC__StreamEncoder
+/** State values for a FLAC__StreamEncoder.
  *
- *  The encoder's state can be obtained by calling FLAC__stream_encoder_get_state().
+ * The encoder's state can be obtained by calling FLAC__stream_encoder_get_state().
+ *
+ * If the encoder gets into any other state besides \c FLAC__STREAM_ENCODER_OK
+ * or \c FLAC__STREAM_ENCODER_UNINITIALIZED, it becomes invalid for encoding and
+ * must be deleted with FLAC__stream_encoder_delete().
  */
 typedef enum {
 
 	FLAC__STREAM_ENCODER_OK = 0,
-	/**< The encoder is in the normal OK state. */
+	/**< The encoder is in the normal OK state and samples can be processed. */
 
+	FLAC__STREAM_ENCODER_UNINITIALIZED,
+	/**< The encoder is in the uninitialized state; one of the
+	 * FLAC__stream_encoder_init_*() functions must be called before samples
+	 * can be processed.
+	 */
+
+	FLAC__STREAM_ENCODER_OGG_ERROR,
+	/**< An error occurred in the underlying Ogg layer.  */
+
 	FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR,
 	/**< An error occurred in the underlying verify stream decoder;
 	 * check FLAC__stream_encoder_get_verify_decoder_state().
@@ -210,49 +262,78 @@
 	 * 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_CLIENT_ERROR,
+	/**< One of the callbacks returned a fatal error. */
 
-	FLAC__STREAM_ENCODER_INVALID_NUMBER_OF_CHANNELS,
+	FLAC__STREAM_ENCODER_IO_ERROR,
+	/**< An I/O error occurred while opening/reading/writing a file.
+	 * Check \c errno.
+	 */
+
+	FLAC__STREAM_ENCODER_FRAMING_ERROR,
+	/**< An error occurred while writing the stream; usually, the
+	 * write_callback returned an error.
+	 */
+
+	FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR
+	/**< Memory allocation failed. */
+
+} 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[];
+
+
+/** Possible return values for the FLAC__stream_encoder_init_*() functions.
+ */
+typedef enum {
+
+	FLAC__STREAM_ENCODER_INIT_STATUS_OK = 0,
+	/**< Initialization was successful. */
+
+	FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR,
+	/**< General failure to set up encoder; call FLAC__stream_encoder_get_state() for cause. */
+
+	FLAC__STREAM_ENCODER_INIT_STATUS_UNSUPPORTED_CONTAINER,
+	/**< The library was not compiled with support for the given container
+	 * format.
+	 */
+
+	FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_CALLBACKS,
+	/**< A required callback was not supplied. */
+
+	FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_NUMBER_OF_CHANNELS,
 	/**< The encoder has an invalid setting for number of channels. */
 
-	FLAC__STREAM_ENCODER_INVALID_BITS_PER_SAMPLE,
+	FLAC__STREAM_ENCODER_INIT_STATUS_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,
+	FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_SAMPLE_RATE,
 	/**< The encoder has an invalid setting for the input sample rate. */
 
-	FLAC__STREAM_ENCODER_INVALID_BLOCK_SIZE,
+	FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_BLOCK_SIZE,
 	/**< The encoder has an invalid setting for the block size. */
 
-	FLAC__STREAM_ENCODER_INVALID_MAX_LPC_ORDER,
+	FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_MAX_LPC_ORDER,
 	/**< The encoder has an invalid setting for the maximum LPC order. */
 
-	FLAC__STREAM_ENCODER_INVALID_QLP_COEFF_PRECISION,
+	FLAC__STREAM_ENCODER_INIT_STATUS_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,
+	FLAC__STREAM_ENCODER_INIT_STATUS_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_INIT_STATUS_NOT_STREAMABLE,
+	/**< The encoder is bound to the <A HREF="../format.html#subset">Subset</A> 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,
+	FLAC__STREAM_ENCODER_INIT_STATUS_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
@@ -261,33 +342,48 @@
 	 * - 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
+	FLAC__STREAM_ENCODER_INIT_STATUS_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__StreamEncoderInitStatus;
 
-} FLAC__StreamEncoderState;
+/** Maps a FLAC__StreamEncoderInitStatus to a C string.
+ *
+ *  Using a FLAC__StreamEncoderInitStatus as the index to this array
+ *  will give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamEncoderInitStatusString[];
 
-/** Maps a FLAC__StreamEncoderState to a C string.
+
+/** Return values for the FLAC__StreamEncoder read callback.
+ */
+typedef enum {
+
+	FLAC__STREAM_ENCODER_READ_STATUS_CONTINUE,
+	/**< The read was OK and decoding can continue. */
+
+	FLAC__STREAM_ENCODER_READ_STATUS_END_OF_STREAM,
+	/**< The read was attempted at the end of the stream. */
+
+	FLAC__STREAM_ENCODER_READ_STATUS_ABORT,
+	/**< An unrecoverable error occurred. */
+
+	FLAC__STREAM_ENCODER_READ_STATUS_UNSUPPORTED
+	/**< Client does not support reading back from the output. */
+
+} FLAC__StreamEncoderReadStatus;
+
+/** Maps a FLAC__StreamEncoderReadStatus to a C string.
  *
- *  Using a FLAC__StreamEncoderState as the index to this array
+ *  Using a FLAC__StreamEncoderReadStatus 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[];
+extern FLAC_API const char * const FLAC__StreamEncoderReadStatusString[];
 
+
 /** Return values for the FLAC__StreamEncoder write callback.
  */
 typedef enum {
@@ -308,6 +404,52 @@
 extern FLAC_API const char * const FLAC__StreamEncoderWriteStatusString[];
 
 
+/** Return values for the FLAC__StreamEncoder seek callback.
+ */
+typedef enum {
+
+	FLAC__STREAM_ENCODER_SEEK_STATUS_OK,
+	/**< The seek was OK and encoding can continue. */
+
+	FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR,
+	/**< An unrecoverable error occurred. */
+
+	FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED
+	/**< Client does not support seeking. */
+
+} FLAC__StreamEncoderSeekStatus;
+
+/** Maps a FLAC__StreamEncoderSeekStatus to a C string.
+ *
+ *  Using a FLAC__StreamEncoderSeekStatus as the index to this array
+ *  will give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamEncoderSeekStatusString[];
+
+
+/** Return values for the FLAC__StreamEncoder tell callback.
+ */
+typedef enum {
+
+	FLAC__STREAM_ENCODER_TELL_STATUS_OK,
+	/**< The tell was OK and encoding can continue. */
+
+	FLAC__STREAM_ENCODER_TELL_STATUS_ERROR,
+	/**< An unrecoverable error occurred. */
+
+	FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED
+	/**< Client does not support seeking. */
+
+} FLAC__StreamEncoderTellStatus;
+
+/** Maps a FLAC__StreamEncoderTellStatus to a C string.
+ *
+ *  Using a FLAC__StreamEncoderTellStatus as the index to this array
+ *  will give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamEncoderTellStatusString[];
+
+
 /***********************************************************************
  *
  * class FLAC__StreamEncoder
@@ -325,34 +467,217 @@
 	struct FLAC__StreamEncoderPrivate *private_; /* avoid the C++ keyword 'private' */
 } FLAC__StreamEncoder;
 
+/** Signature for the read callback.
+ *
+ *  A function pointer matching this signature must be passed to
+ *  FLAC__stream_encoder_init_ogg_stream() if seeking is supported.
+ *  The supplied function will be called when the encoder needs to read back
+ *  encoded data.  This happens during the metadata callback, when the encoder
+ *  has to read, modify, and rewrite the metadata (e.g. seekpoints) gathered
+ *  while encoding.  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__StreamEncoderReadStatus.
+ *
+ * Here is an example of a read callback for stdio streams:
+ * \code
+ * FLAC__StreamEncoderReadStatus read_cb(const FLAC__StreamEncoder *encoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
+ * {
+ *   FILE *file = ((MyClientData*)client_data)->file;
+ *   if(*bytes > 0) {
+ *     *bytes = fread(buffer, sizeof(FLAC__byte), *bytes, file);
+ *     if(ferror(file))
+ *       return FLAC__STREAM_ENCODER_READ_STATUS_ABORT;
+ *     else if(*bytes == 0)
+ *       return FLAC__STREAM_ENCODER_READ_STATUS_END_OF_STREAM;
+ *     else
+ *       return FLAC__STREAM_ENCODER_READ_STATUS_CONTINUE;
+ *   }
+ *   else
+ *     return FLAC__STREAM_ENCODER_READ_STATUS_ABORT;
+ * }
+ * \endcode
+ *
+ * \note In general, FLAC__StreamEncoder functions which change the
+ * state should not be called on the \a encoder while in the callback.
+ *
+ * \param  encoder  The encoder instance calling the callback.
+ * \param  buffer   A pointer to a location for the callee to store
+ *                  data to be encoded.
+ * \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_encoder_set_client_data().
+ * \retval FLAC__StreamEncoderReadStatus
+ *    The callee's return status.
+ */
+typedef FLAC__StreamEncoderReadStatus (*FLAC__StreamEncoderReadCallback)(const FLAC__StreamEncoder *encoder, FLAC__byte buffer[], size_t *bytes, void *client_data);
+
 /** Signature for the write callback.
- *  See FLAC__stream_encoder_set_write_callback() for more info.
  *
+ *  A function pointer matching this signature must be passed to
+ *  FLAC__stream_encoder_init*_stream().  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 it indicates that the write
+ *  callback is being called to write metadata.
+ *
+ * \note
+ * Unlike when writing to native FLAC, when writing to Ogg FLAC the
+ * write callback will be called twice when writing each audio
+ * frame; once for the page header, and once for the page body.
+ * When writing the page header, the \a samples argument to the
+ * write callback will be \c 0.
+ *
+ * \note In general, FLAC__StreamEncoder functions which change the
+ * state should not be called on the \a encoder while in the callback.
+ *
  * \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().
+ *                  \c 0 has a special meaning; see above.
  * \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().
+ *                      FLAC__stream_encoder_init_*().
  * \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);
+typedef FLAC__StreamEncoderWriteStatus (*FLAC__StreamEncoderWriteCallback)(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame, void *client_data);
 
+/** Signature for the seek callback.
+ *
+ *  A function pointer matching this signature may be passed to
+ *  FLAC__stream_encoder_init*_stream().  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.
+ *
+ * Here is an example of a seek callback for stdio streams:
+ * \code
+ * FLAC__StreamEncoderSeekStatus seek_cb(const FLAC__StreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data)
+ * {
+ *   FILE *file = ((MyClientData*)client_data)->file;
+ *   if(file == stdin)
+ *     return FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED;
+ *   else if(fseeko(file, (off_t)absolute_byte_offset, SEEK_SET) < 0)
+ *     return FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR;
+ *   else
+ *     return FLAC__STREAM_ENCODER_SEEK_STATUS_OK;
+ * }
+ * \endcode
+ *
+ * \note In general, FLAC__StreamEncoder functions which change the
+ * state should not be called on the \a encoder while in the callback.
+ *
+ * \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__stream_encoder_init_*().
+ * \retval FLAC__StreamEncoderSeekStatus
+ *    The callee's return status.
+ */
+typedef FLAC__StreamEncoderSeekStatus (*FLAC__StreamEncoderSeekCallback)(const FLAC__StreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data);
+
+/** Signature for the tell callback.
+ *
+ *  A function pointer matching this signature may be passed to
+ *  FLAC__stream_encoder_init*_stream().  The supplied function will be called
+ *  when the encoder needs to know the current position of the output stream.
+ *
+ * \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.
+ *
+ * Here is an example of a tell callback for stdio streams:
+ * \code
+ * FLAC__StreamEncoderTellStatus tell_cb(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
+ * {
+ *   FILE *file = ((MyClientData*)client_data)->file;
+ *   off_t pos;
+ *   if(file == stdin)
+ *     return FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED;
+ *   else if((pos = ftello(file)) < 0)
+ *     return FLAC__STREAM_ENCODER_TELL_STATUS_ERROR;
+ *   else {
+ *     *absolute_byte_offset = (FLAC__uint64)pos;
+ *     return FLAC__STREAM_ENCODER_TELL_STATUS_OK;
+ *   }
+ * }
+ * \endcode
+ *
+ * \note In general, FLAC__StreamEncoder functions which change the
+ * state should not be called on the \a encoder while in the callback.
+ *
+ * \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__stream_encoder_init_*().
+ * \retval FLAC__StreamEncoderTellStatus
+ *    The callee's return status.
+ */
+typedef FLAC__StreamEncoderTellStatus (*FLAC__StreamEncoderTellCallback)(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data);
+
 /** Signature for the metadata callback.
- *  See FLAC__stream_encoder_set_metadata_callback() for more info.
  *
+ *  A function pointer matching this signature may be passed to
+ *  FLAC__stream_encoder_init*_stream().  The supplied function will be called
+ *  once at the end of encoding with the populated STREAMINFO structure.  This
+ *  is so the client 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 In general, FLAC__StreamEncoder functions which change the
+ * state should not be called on the \a encoder while in the callback.
+ *
  * \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().
+ *                      FLAC__stream_encoder_init_*().
  */
 typedef void (*FLAC__StreamEncoderMetadataCallback)(const FLAC__StreamEncoder *encoder, const FLAC__StreamMetadata *metadata, void *client_data);
 
+/** Signature for the progress callback.
+ *
+ *  A function pointer matching this signature may be passed to
+ *  FLAC__stream_encoder_init*_file() or FLAC__stream_encoder_init*_FILE().
+ *  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__stream_encoder_set_total_samples_estimate().
+ *
+ * \note In general, FLAC__StreamEncoder functions which change the
+ * state should not be called on the \a encoder while in the callback.
+ *
+ * \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__stream_encoder_init_*().
+ */
+typedef void (*FLAC__StreamEncoderProgressCallback)(const FLAC__StreamEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_estimate, void *client_data);
 
+
 /***********************************************************************
  *
  * Class constructor/destructor
@@ -366,7 +691,7 @@
  * \retval FLAC__StreamEncoder*
  *    \c NULL if there was an error allocating memory, else the new instance.
  */
-FLAC_API FLAC__StreamEncoder *FLAC__stream_encoder_new();
+FLAC_API FLAC__StreamEncoder *FLAC__stream_encoder_new(void);
 
 /** Free an encoder instance.  Deletes the object pointed to by \a encoder.
  *
@@ -383,6 +708,25 @@
  *
  ***********************************************************************/
 
+/** Set the serial number for the FLAC stream to use in the Ogg container.
+ *
+ * \note
+ * This does not need to be set for native FLAC encoding.
+ *
+ * \note
+ * It is recommended to set a serial number explicitly as the default of '0'
+ * may collide with other streams.
+ *
+ * \default \c 0
+ * \param  encoder        An encoder instance to set.
+ * \param  serial_number  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_ogg_serial_number(FLAC__StreamEncoder *encoder, long serial_number);
+
 /** 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,
@@ -399,9 +743,9 @@
  */
 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
+/** Set the <A HREF="../format.html#subset">Subset</A> flag.  If \c true,
+ *  the encoder will comply with the Subset 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.
  *
@@ -417,38 +761,37 @@
  */
 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.
+/** Set the number of channels to be encoded.
  *
- * \default \c false
+ * \default \c 2
  * \param  encoder  An encoder instance to set.
- * \param  value    Flag value (see above).
+ * \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_mid_side_stereo(FLAC__StreamEncoder *encoder, FLAC__bool value);
+FLAC_API FLAC__bool FLAC__stream_encoder_set_channels(FLAC__StreamEncoder *encoder, unsigned 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.
+/** Set the sample resolution of the input to be encoded.
  *
- * \default \c false
+ * \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    Flag value (see above).
+ * \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_loose_mid_side_stereo(FLAC__StreamEncoder *encoder, FLAC__bool value);
+FLAC_API FLAC__bool FLAC__stream_encoder_set_bits_per_sample(FLAC__StreamEncoder *encoder, unsigned value);
 
-/** Set the number of channels to be encoded.
+/** Set the sample rate (in Hz) of the input to be encoded.
  *
- * \default \c 2
+ * \default \c 44100
  * \param  encoder  An encoder instance to set.
  * \param  value    See above.
  * \assert
@@ -456,15 +799,62 @@
  * \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);
+FLAC_API FLAC__bool FLAC__stream_encoder_set_sample_rate(FLAC__StreamEncoder *encoder, unsigned value);
 
-/** Set the sample resolution of the input to be encoded.
+/** Set the compression level
  *
- * \warning
- * Do not feed the encoder data that is wider than the value you
- * set here or you will generate an invalid stream.
+ * The compression level is roughly proportional to the amount of effort
+ * the encoder expends to compress the file.  A higher level usually
+ * means more computation but higher compression.  The default level is
+ * suitable for most applications.
  *
- * \default \c 16
+ * Currently the levels range from \c 0 (fastest, least compression) to
+ * \c 8 (slowest, most compression).  A value larger than \c 8 will be
+ * treated as \c 8.
+ *
+ * This function automatically calls the following other \c _set_
+ * functions with appropriate values, so the client does not need to
+ * unless it specifically wants to override them:
+ * - FLAC__stream_encoder_set_do_mid_side_stereo()
+ * - FLAC__stream_encoder_set_loose_mid_side_stereo()
+ * - FLAC__stream_encoder_set_apodization()
+ * - FLAC__stream_encoder_set_max_lpc_order()
+ * - FLAC__stream_encoder_set_qlp_coeff_precision()
+ * - FLAC__stream_encoder_set_do_qlp_coeff_prec_search()
+ * - FLAC__stream_encoder_set_do_escape_coding()
+ * - FLAC__stream_encoder_set_do_exhaustive_model_search()
+ * - FLAC__stream_encoder_set_min_residual_partition_order()
+ * - FLAC__stream_encoder_set_max_residual_partition_order()
+ * - FLAC__stream_encoder_set_rice_parameter_search_dist()
+ *
+ * The actual values set for each level are:
+ * <table>
+ * <tr>
+ *  <td><b>level</b></td>
+ *  <td>do mid-side stereo</td>
+ *  <td>loose mid-side stereo</td>
+ *  <td>apodization</td>
+ *  <td>max lpc order</td>
+ *  <td>qlp coeff precision</td>
+ *  <td>qlp coeff prec search</td>
+ *  <td>escape coding</td>
+ *  <td>exhaustive model search</td>
+ *  <td>min residual partition order</td>
+ *  <td>max residual partition order</td>
+ *  <td>rice parameter search dist</td>
+ * </tr>
+ * <tr>  <td><b>0</b></td> <td>false</td> <td>false</td> <td>tukey(0.5)<td>                                     <td>0</td>  <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>3</td> <td>0</td> </tr>
+ * <tr>  <td><b>1</b></td> <td>true</td>  <td>true</td>  <td>tukey(0.5)<td>                                     <td>0</td>  <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>3</td> <td>0</td> </tr>
+ * <tr>  <td><b>2</b></td> <td>true</td>  <td>false</td> <td>tukey(0.5)<td>                                     <td>0</td>  <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>3</td> <td>0</td> </tr>
+ * <tr>  <td><b>3</b></td> <td>false</td> <td>false</td> <td>tukey(0.5)<td>                                     <td>6</td>  <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>4</td> <td>0</td> </tr>
+ * <tr>  <td><b>4</b></td> <td>true</td>  <td>true</td>  <td>tukey(0.5)<td>                                     <td>8</td>  <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>4</td> <td>0</td> </tr>
+ * <tr>  <td><b>5</b></td> <td>true</td>  <td>false</td> <td>tukey(0.5)<td>                                     <td>8</td>  <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>5</td> <td>0</td> </tr>
+ * <tr>  <td><b>6</b></td> <td>true</td>  <td>false</td> <td>tukey(0.5);partial_tukey(2)<td>                    <td>8</td>  <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>6</td> <td>0</td> </tr>
+ * <tr>  <td><b>7</b></td> <td>true</td>  <td>false</td> <td>tukey(0.5);partial_tukey(2)<td>                    <td>12</td> <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>6</td> <td>0</td> </tr>
+ * <tr>  <td><b>8</b></td> <td>true</td>  <td>false</td> <td>tukey(0.5);partial_tukey(2);punchout_tukey(3)</td> <td>12</td> <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>6</td> <td>0</td> </tr>
+ * </table>
+ *
+ * \default \c 5
  * \param  encoder  An encoder instance to set.
  * \param  value    See above.
  * \assert
@@ -472,11 +862,14 @@
  * \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);
+FLAC_API FLAC__bool FLAC__stream_encoder_set_compression_level(FLAC__StreamEncoder *encoder, unsigned value);
 
-/** Set the sample rate (in Hz) of the input to be encoded.
+/** Set the blocksize to use while encoding.
  *
- * \default \c 44100
+ * The number of samples to use per frame.  Use \c 0 to let the encoder
+ * estimate a blocksize; this is usually best.
+ *
+ * \default \c 0
  * \param  encoder  An encoder instance to set.
  * \param  value    See above.
  * \assert
@@ -484,20 +877,104 @@
  * \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);
+FLAC_API FLAC__bool FLAC__stream_encoder_set_blocksize(FLAC__StreamEncoder *encoder, unsigned value);
 
-/** Set the blocksize to use while encoding.
+/** Set to \c true to enable mid-side encoding on stereo input.  The
+ *  number of channels must be 2 for this to have any effect.  Set to
+ *  \c false to use only independent channel coding.
  *
- * \default \c 1152
+ * \default \c false
  * \param  encoder  An encoder instance to set.
- * \param  value    See above.
+ * \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_blocksize(FLAC__StreamEncoder *encoder, unsigned value);
+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.  Set to \c false to use
+ *  exhaustive searching.  Setting this to \c true requires
+ *  FLAC__stream_encoder_set_do_mid_side_stereo() to also be set to
+ *  \c true in order to have any effect.
+ *
+ * \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);
+
+/** Sets the apodization function(s) the encoder will use when windowing
+ *  audio data for LPC analysis.
+ *
+ * The \a specification is a plain ASCII string which specifies exactly
+ * which functions to use.  There may be more than one (up to 32),
+ * separated by \c ';' characters.  Some functions take one or more
+ * comma-separated arguments in parentheses.
+ *
+ * The available functions are \c bartlett, \c bartlett_hann,
+ * \c blackman, \c blackman_harris_4term_92db, \c connes, \c flattop,
+ * \c gauss(STDDEV), \c hamming, \c hann, \c kaiser_bessel, \c nuttall,
+ * \c rectangle, \c triangle, \c tukey(P), \c partial_tukey(n[/ov[/P]]),
+ * \c punchout_tukey(n[/ov[/P]]), \c welch.
+ *
+ * For \c gauss(STDDEV), STDDEV specifies the standard deviation
+ * (0<STDDEV<=0.5).
+ *
+ * For \c tukey(P), P specifies the fraction of the window that is
+ * tapered (0<=P<=1).  P=0 corresponds to \c rectangle and P=1
+ * corresponds to \c hann.
+ *
+ * Specifying \c partial_tukey or \c punchout_tukey works a little
+ * different. These do not specify a single apodization function, but
+ * a series of them with some overlap. partial_tukey specifies a series
+ * of small windows (all treated separately) while punchout_tukey
+ * specifies a series of windows that have a hole in them. In this way,
+ * the predictor is constructed with only a part of the block, which
+ * helps in case a block consists of dissimilar parts.
+ *
+ * The three parameters that can be specified for the functions are
+ * n, ov and P. n is the number of functions to add, ov is the overlap
+ * of the windows in case of partial_tukey and the overlap in the gaps
+ * in case of punchout_tukey. P is the fraction of the window that is
+ * tapered, like with a regular tukey window. The function can be
+ * specified with only a number, a number and an overlap, or a number
+ * an overlap and a P, for example, partial_tukey(3), partial_tukey(3/0.3)
+ * and partial_tukey(3/0.3/0.5) are all valid. ov should be smaller than 1
+ * and can be negative.
+ *
+ * Example specifications are \c "blackman" or
+ * \c "hann;triangle;tukey(0.5);tukey(0.25);tukey(0.125)"
+ *
+ * Any function that is specified erroneously is silently dropped.  Up
+ * to 32 functions are kept, the rest are dropped.  If the specification
+ * is empty the encoder defaults to \c "tukey(0.5)".
+ *
+ * When more than one function is specified, then for every subframe the
+ * encoder will try each of them separately and choose the window that
+ * results in the smallest compressed subframe.
+ *
+ * Note that each function specified causes the encoder to occupy a
+ * floating point array in which to store the window. Also note that the
+ * values of P, STDDEV and ov are locale-specific, so if the comma
+ * separator specified by the locale is a comma, a comma should be used.
+ *
+ * \default \c "tukey(0.5)"
+ * \param  encoder        An encoder instance to set.
+ * \param  specification  See above.
+ * \assert
+ *    \code encoder != NULL \endcode
+ *    \code specification != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_apodization(FLAC__StreamEncoder *encoder, const char *specification);
+
 /** Set the maximum LPC order, or \c 0 to use only the fixed predictors.
  *
  * \default \c 0
@@ -645,14 +1122,15 @@
 /** 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.
+ *  the encoder may need to change the \a is_last flag inside them, and
+ *  in some cases update seek point offsets.  Otherwise, the encoder will
+ *  not modify or free the blocks.  It is up to the caller to free the
+ *  metadata blocks after encoding finishes.
  *
  * \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.
+ * The encoder stores only copies of the pointers in the \a metadata array;
+ * the metadata blocks themselves must survive at least until after
+ * FLAC__stream_encoder_finish() returns.  Do not free the blocks until then.
  *
  * \note
  * The STREAMINFO block is always written and no STREAMINFO block may
@@ -660,13 +1138,37 @@
  *
  * \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())
+ * in the \a metadata array, but the client has specified that it does not
+ * support seeking, then the SEEKTABLE will be written verbatim.  However
+ * by itself this is not very useful as the client will not know the stream
+ * offsets for the seekpoints ahead of time.  In order to get a proper
+ * seektable the client must support seeking.  See next note.
  *
  * \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.  If the
+ * client has specified that it supports seeking by providing a seek
+ * callback to FLAC__stream_encoder_init_stream() or both seek AND read
+ * callback to FLAC__stream_encoder_init_ogg_stream() (or by using
+ * FLAC__stream_encoder_init*_file() or FLAC__stream_encoder_init*_FILE()),
+ * then while it is encoding the encoder will fill the stream offsets 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_*().  If the client does
+ * not support seeking, the SEEKTABLE will have inaccurate offsets which
+ * will slow down or remove the ability to seek in the FLAC stream.
+ *
+ * \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.
+ *
+ * \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
@@ -674,6 +1176,19 @@
  * block is present in the \a metadata array, libFLAC will write an
  * empty one, containing only the vendor string.
  *
+ * \note The Ogg FLAC mapping requires that the VORBIS_COMMENT block be
+ * the second metadata block of the stream.  The encoder already supplies
+ * the STREAMINFO block automatically.  If \a metadata does not contain a
+ * VORBIS_COMMENT block, the encoder will supply that too.  Otherwise, if
+ * \a metadata does contain a VORBIS_COMMENT block and it is not the
+ * first, the init function will reorder \a metadata by moving the
+ * VORBIS_COMMENT block to the front; the relative ordering of the other
+ * blocks will remain as they were.
+ *
+ * \note The Ogg FLAC mapping limits the number of metadata blocks per
+ * stream to \c 65535.  If \a num_blocks exceeds this the function will
+ * return \c false.
+ *
  * \default \c NULL, 0
  * \param  encoder     An encoder instance to set.
  * \param  metadata    See above.
@@ -682,71 +1197,11 @@
  *    \code encoder != NULL \endcode
  * \retval FLAC__bool
  *    \c false if the encoder is already initialized, else \c true.
+ *    \c false if the encoder is already initialized, or if
+ *    \a num_blocks > 65535 if encoding to Ogg FLAC, 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.
@@ -811,7 +1266,7 @@
  */
 FLAC_API FLAC__bool FLAC__stream_encoder_get_verify(const FLAC__StreamEncoder *encoder);
 
-/** Get the "streamable subset" flag.
+/** Get the <A HREF="../format.html#subset>Subset</A> flag.
  *
  * \param  encoder  An encoder instance to query.
  * \assert
@@ -821,26 +1276,6 @@
  */
 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.
@@ -881,6 +1316,26 @@
  */
 FLAC_API unsigned FLAC__stream_encoder_get_blocksize(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 maximum LPC order setting.
  *
  * \param  encoder  An encoder instance to query.
@@ -964,7 +1419,7 @@
 /** 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.
+ *  other way of knowing how many samples the client will encode.
  *
  * \param  encoder  An encoder instance to set.
  * \assert
@@ -974,26 +1429,271 @@
  */
 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
+/** Initialize the encoder instance to encode native FLAC streams.
+ *
+ *  This flavor of initialization sets up the encoder to encode to a
+ *  native FLAC stream. I/O is performed via callbacks to the client.
+ *  For encoding to a plain file via filename or open \c FILE*,
+ *  FLAC__stream_encoder_init_file() and FLAC__stream_encoder_init_FILE()
+ *  provide a simpler interface.
+ *
+ *  This function 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
+ *  or FLAC__stream_encoder_process_interleaved().
  *  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.
+ *  The call to FLAC__stream_encoder_init_stream() 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.
+ * \param  encoder            An uninitialized encoder instance.
+ * \param  write_callback     See FLAC__StreamEncoderWriteCallback.  This
+ *                            pointer must not be \c NULL.
+ * \param  seek_callback      See FLAC__StreamEncoderSeekCallback.  This
+ *                            pointer may be \c NULL if seeking is not
+ *                            supported.  The encoder uses seeking to go back
+ *                            and write some some stream statistics to the
+ *                            STREAMINFO block; this is recommended but not
+ *                            necessary to create a valid FLAC stream.  If
+ *                            \a seek_callback is not \c NULL then a
+ *                            \a tell_callback must also be supplied.
+ *                            Alternatively, a dummy seek callback that just
+ *                            returns \c FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED
+ *                            may also be supplied, all though this is slightly
+ *                            less efficient for the encoder.
+ * \param  tell_callback      See FLAC__StreamEncoderTellCallback.  This
+ *                            pointer may be \c NULL if seeking is not
+ *                            supported.  If \a seek_callback is \c NULL then
+ *                            this argument will be ignored.  If
+ *                            \a seek_callback is not \c NULL then a
+ *                            \a tell_callback must also be supplied.
+ *                            Alternatively, a dummy tell callback that just
+ *                            returns \c FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED
+ *                            may also be supplied, all though this is slightly
+ *                            less efficient for the encoder.
+ * \param  metadata_callback  See FLAC__StreamEncoderMetadataCallback.  This
+ *                            pointer may be \c NULL if the callback is not
+ *                            desired.  If the client provides a seek callback,
+ *                            this function is not necessary as the encoder
+ *                            will automatically seek back and update the
+ *                            STREAMINFO block.  It may also be \c NULL if the
+ *                            client does not support seeking, since it will
+ *                            have no way of going back to update the
+ *                            STREAMINFO.  However the client can still supply
+ *                            a callback if it would like to know the details
+ *                            from the STREAMINFO.
+ * \param  client_data        This value will be supplied to callbacks in their
+ *                            \a client_data argument.
  * \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.
+ * \retval FLAC__StreamEncoderInitStatus
+ *    \c FLAC__STREAM_ENCODER_INIT_STATUS_OK if initialization was successful;
+ *    see FLAC__StreamEncoderInitStatus for the meanings of other return values.
  */
-FLAC_API FLAC__StreamEncoderState FLAC__stream_encoder_init(FLAC__StreamEncoder *encoder);
+FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_stream(FLAC__StreamEncoder *encoder, FLAC__StreamEncoderWriteCallback write_callback, FLAC__StreamEncoderSeekCallback seek_callback, FLAC__StreamEncoderTellCallback tell_callback, FLAC__StreamEncoderMetadataCallback metadata_callback, void *client_data);
 
+/** Initialize the encoder instance to encode Ogg FLAC streams.
+ *
+ *  This flavor of initialization sets up the encoder to encode to a FLAC
+ *  stream in an Ogg container.  I/O is performed via callbacks to the
+ *  client.  For encoding to a plain file via filename or open \c FILE*,
+ *  FLAC__stream_encoder_init_ogg_file() and FLAC__stream_encoder_init_ogg_FILE()
+ *  provide a simpler interface.
+ *
+ *  This function 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().
+ *  initialization succeeded.
+ *
+ *  The call to FLAC__stream_encoder_init_ogg_stream() currently will also
+ *  immediately call the write callback several times to write the metadata
+ *  packets.
+ *
+ * \param  encoder            An uninitialized encoder instance.
+ * \param  read_callback      See FLAC__StreamEncoderReadCallback.  This
+ *                            pointer must not be \c NULL if \a seek_callback
+ *                            is non-NULL since they are both needed to be
+ *                            able to write data back to the Ogg FLAC stream
+ *                            in the post-encode phase.
+ * \param  write_callback     See FLAC__StreamEncoderWriteCallback.  This
+ *                            pointer must not be \c NULL.
+ * \param  seek_callback      See FLAC__StreamEncoderSeekCallback.  This
+ *                            pointer may be \c NULL if seeking is not
+ *                            supported.  The encoder uses seeking to go back
+ *                            and write some some stream statistics to the
+ *                            STREAMINFO block; this is recommended but not
+ *                            necessary to create a valid FLAC stream.  If
+ *                            \a seek_callback is not \c NULL then a
+ *                            \a tell_callback must also be supplied.
+ *                            Alternatively, a dummy seek callback that just
+ *                            returns \c FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED
+ *                            may also be supplied, all though this is slightly
+ *                            less efficient for the encoder.
+ * \param  tell_callback      See FLAC__StreamEncoderTellCallback.  This
+ *                            pointer may be \c NULL if seeking is not
+ *                            supported.  If \a seek_callback is \c NULL then
+ *                            this argument will be ignored.  If
+ *                            \a seek_callback is not \c NULL then a
+ *                            \a tell_callback must also be supplied.
+ *                            Alternatively, a dummy tell callback that just
+ *                            returns \c FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED
+ *                            may also be supplied, all though this is slightly
+ *                            less efficient for the encoder.
+ * \param  metadata_callback  See FLAC__StreamEncoderMetadataCallback.  This
+ *                            pointer may be \c NULL if the callback is not
+ *                            desired.  If the client provides a seek callback,
+ *                            this function is not necessary as the encoder
+ *                            will automatically seek back and update the
+ *                            STREAMINFO block.  It may also be \c NULL if the
+ *                            client does not support seeking, since it will
+ *                            have no way of going back to update the
+ *                            STREAMINFO.  However the client can still supply
+ *                            a callback if it would like to know the details
+ *                            from the STREAMINFO.
+ * \param  client_data        This value will be supplied to callbacks in their
+ *                            \a client_data argument.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__StreamEncoderInitStatus
+ *    \c FLAC__STREAM_ENCODER_INIT_STATUS_OK if initialization was successful;
+ *    see FLAC__StreamEncoderInitStatus for the meanings of other return values.
+ */
+FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_ogg_stream(FLAC__StreamEncoder *encoder, FLAC__StreamEncoderReadCallback read_callback, FLAC__StreamEncoderWriteCallback write_callback, FLAC__StreamEncoderSeekCallback seek_callback, FLAC__StreamEncoderTellCallback tell_callback, FLAC__StreamEncoderMetadataCallback metadata_callback, void *client_data);
+
+/** Initialize the encoder instance to encode native FLAC files.
+ *
+ *  This flavor of initialization sets up the encoder to encode to a
+ *  plain native FLAC file.  For non-stdio streams, you must use
+ *  FLAC__stream_encoder_init_stream() and provide callbacks for the I/O.
+ *
+ *  This function 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().
+ *  initialization succeeded.
+ *
+ * \param  encoder            An uninitialized encoder instance.
+ * \param  file               An open file.  The file should have been opened
+ *                            with mode \c "w+b" and rewound.  The file
+ *                            becomes owned by the encoder and should not be
+ *                            manipulated by the client while encoding.
+ *                            Unless \a file is \c stdout, it will be closed
+ *                            when FLAC__stream_encoder_finish() is called.
+ *                            Note however that a proper SEEKTABLE cannot be
+ *                            created when encoding to \c stdout since it is
+ *                            not seekable.
+ * \param  progress_callback  See FLAC__StreamEncoderProgressCallback.  This
+ *                            pointer may be \c NULL if the callback is not
+ *                            desired.
+ * \param  client_data        This value will be supplied to callbacks in their
+ *                            \a client_data argument.
+ * \assert
+ *    \code encoder != NULL \endcode
+ *    \code file != NULL \endcode
+ * \retval FLAC__StreamEncoderInitStatus
+ *    \c FLAC__STREAM_ENCODER_INIT_STATUS_OK if initialization was successful;
+ *    see FLAC__StreamEncoderInitStatus for the meanings of other return values.
+ */
+FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_FILE(FLAC__StreamEncoder *encoder, FILE *file, FLAC__StreamEncoderProgressCallback progress_callback, void *client_data);
+
+/** Initialize the encoder instance to encode Ogg FLAC files.
+ *
+ *  This flavor of initialization sets up the encoder to encode to a
+ *  plain Ogg FLAC file.  For non-stdio streams, you must use
+ *  FLAC__stream_encoder_init_ogg_stream() and provide callbacks for the I/O.
+ *
+ *  This function 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().
+ *  initialization succeeded.
+ *
+ * \param  encoder            An uninitialized encoder instance.
+ * \param  file               An open file.  The file should have been opened
+ *                            with mode \c "w+b" and rewound.  The file
+ *                            becomes owned by the encoder and should not be
+ *                            manipulated by the client while encoding.
+ *                            Unless \a file is \c stdout, it will be closed
+ *                            when FLAC__stream_encoder_finish() is called.
+ *                            Note however that a proper SEEKTABLE cannot be
+ *                            created when encoding to \c stdout since it is
+ *                            not seekable.
+ * \param  progress_callback  See FLAC__StreamEncoderProgressCallback.  This
+ *                            pointer may be \c NULL if the callback is not
+ *                            desired.
+ * \param  client_data        This value will be supplied to callbacks in their
+ *                            \a client_data argument.
+ * \assert
+ *    \code encoder != NULL \endcode
+ *    \code file != NULL \endcode
+ * \retval FLAC__StreamEncoderInitStatus
+ *    \c FLAC__STREAM_ENCODER_INIT_STATUS_OK if initialization was successful;
+ *    see FLAC__StreamEncoderInitStatus for the meanings of other return values.
+ */
+FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_ogg_FILE(FLAC__StreamEncoder *encoder, FILE *file, FLAC__StreamEncoderProgressCallback progress_callback, void *client_data);
+
+/** Initialize the encoder instance to encode native FLAC files.
+ *
+ *  This flavor of initialization sets up the encoder to encode to a plain
+ *  FLAC file.  If POSIX fopen() semantics are not sufficient (for example,
+ *  with Unicode filenames on Windows), you must use
+ *  FLAC__stream_encoder_init_FILE(), or FLAC__stream_encoder_init_stream()
+ *  and provide callbacks for the I/O.
+ *
+ *  This function 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().
+ *  initialization succeeded.
+ *
+ * \param  encoder            An uninitialized encoder instance.
+ * \param  filename           The name of the file to encode to.  The file will
+ *                            be opened with fopen().  Use \c NULL to encode to
+ *                            \c stdout.  Note however that a proper SEEKTABLE
+ *                            cannot be created when encoding to \c stdout since
+ *                            it is not seekable.
+ * \param  progress_callback  See FLAC__StreamEncoderProgressCallback.  This
+ *                            pointer may be \c NULL if the callback is not
+ *                            desired.
+ * \param  client_data        This value will be supplied to callbacks in their
+ *                            \a client_data argument.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__StreamEncoderInitStatus
+ *    \c FLAC__STREAM_ENCODER_INIT_STATUS_OK if initialization was successful;
+ *    see FLAC__StreamEncoderInitStatus for the meanings of other return values.
+ */
+FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_file(FLAC__StreamEncoder *encoder, const char *filename, FLAC__StreamEncoderProgressCallback progress_callback, void *client_data);
+
+/** Initialize the encoder instance to encode Ogg FLAC files.
+ *
+ *  This flavor of initialization sets up the encoder to encode to a plain
+ *  Ogg FLAC file.  If POSIX fopen() semantics are not sufficient (for example,
+ *  with Unicode filenames on Windows), you must use
+ *  FLAC__stream_encoder_init_ogg_FILE(), or FLAC__stream_encoder_init_ogg_stream()
+ *  and provide callbacks for the I/O.
+ *
+ *  This function 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().
+ *  initialization succeeded.
+ *
+ * \param  encoder            An uninitialized encoder instance.
+ * \param  filename           The name of the file to encode to.  The file will
+ *                            be opened with fopen().  Use \c NULL to encode to
+ *                            \c stdout.  Note however that a proper SEEKTABLE
+ *                            cannot be created when encoding to \c stdout since
+ *                            it is not seekable.
+ * \param  progress_callback  See FLAC__StreamEncoderProgressCallback.  This
+ *                            pointer may be \c NULL if the callback is not
+ *                            desired.
+ * \param  client_data        This value will be supplied to callbacks in their
+ *                            \a client_data argument.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__StreamEncoderInitStatus
+ *    \c FLAC__STREAM_ENCODER_INIT_STATUS_OK if initialization was successful;
+ *    see FLAC__StreamEncoderInitStatus for the meanings of other return values.
+ */
+FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_ogg_file(FLAC__StreamEncoder *encoder, const char *filename, FLAC__StreamEncoderProgressCallback progress_callback, void *client_data);
+
 /** Finish the encoding process.
  *  Flushes the encoding buffer, releases resources, resets the encoder
  *  settings to their defaults, and returns the encoder state to
@@ -1001,23 +1701,41 @@
  *  one or more write callbacks before returning, and will generate
  *  a metadata callback.
  *
+ *  Note that in the course of processing the last frame, errors can
+ *  occur, so the caller should be sure to check the return value to
+ *  ensure the file was encoded properly.
+ *
  *  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()
+ *  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
+ * \retval FLAC__bool
+ *    \c false if an error occurred processing the last frame; or if verify
+ *    mode is set (see FLAC__stream_encoder_set_verify()), there was a
+ *    verify mismatch; else \c true.  If \c false, caller should check the
+ *    state with FLAC__stream_encoder_get_state() for more information
+ *    about the error.
  */
-FLAC_API void FLAC__stream_encoder_finish(FLAC__StreamEncoder *encoder);
+FLAC_API FLAC__bool 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.
+ *  but each channel should have the same number of samples.  Each sample
+ *  should be a signed integer, right-justified to the resolution set by
+ *  FLAC__stream_encoder_set_bits_per_sample().  For example, if the
+ *  resolution is 16 bits per sample, the samples should all be in the
+ *  range [-32768,32767].
  *
+ *  For applications where channel order is important, channels must
+ *  follow the order as described in the
+ *  <A HREF="../format.html#frame_header">frame header</A>.
+ *
  * \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.
@@ -1037,7 +1755,15 @@
  *  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.
+ *  and the last value channelN_sampleM.  Each sample should be a signed
+ *  integer, right-justified to the resolution set by
+ *  FLAC__stream_encoder_set_bits_per_sample().  For example, if the
+ *  resolution is 16 bits per sample, the samples should all be in the
+ *  range [-32768,32767].
+ *
+ *  For applications where channel order is important, channels must
+ *  follow the order as described in the
+ *  <A HREF="../format.html#frame_header">frame header</A>.
  *
  * \param  encoder  An initialized encoder instance in the OK state.
  * \param  buffer   An array of channel-interleaved data (see above).
--- a/sys/src/cmd/audio/libFLAC/bitbuffer.c
+++ /dev/null
@@ -1,2530 +1,0 @@
-/* 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(void)
-{
-	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");
-		}
-	}
-}
--- a/sys/src/cmd/audio/libFLAC/bitmath.c
+++ b/sys/src/cmd/audio/libFLAC/bitmath.c
@@ -1,5 +1,6 @@
 /* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2001,2002,2003,2004  Josh Coalson
+ * Copyright (C) 2001-2009  Josh Coalson
+ * Copyright (C) 2011-2014  Xiph.Org Foundation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -29,39 +30,11 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "private/bitmath.h"
-#include "FLAC/assert.h"
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
 
-/* 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;
-}
+#include "private/bitmath.h"
 
 /* An example of what FLAC__bitmath_silog2() computes:
  *
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/bitreader.c
@@ -1,0 +1,1059 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2014  Xiph.Org Foundation
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include "private/bitmath.h"
+#include "private/bitreader.h"
+#include "private/crc.h"
+#include "private/macros.h"
+#include "FLAC/assert.h"
+#include "share/compat.h"
+#include "share/endswap.h"
+
+/* Things should be fastest when this matches the machine word size */
+/* WATCHOUT: if you change this you must also change the following #defines down to FLAC__clz_uint32 below to match */
+/* WATCHOUT: there are a few places where the code will not work unless uint32_t is >= 32 bits wide */
+/*           also, some sections currently only have fast versions for 4 or 8 bytes per word */
+#define FLAC__BYTES_PER_WORD 4		/* sizeof uint32_t */
+#define FLAC__BITS_PER_WORD (8 * FLAC__BYTES_PER_WORD)
+#define FLAC__WORD_ALL_ONES ((FLAC__uint32)0xffffffff)
+/* SWAP_BE_WORD_TO_HOST swaps bytes in a uint32_t (which is always big-endian) if necessary to match host byte order */
+#if WORDS_BIGENDIAN
+#define SWAP_BE_WORD_TO_HOST(x) (x)
+#else
+#define SWAP_BE_WORD_TO_HOST(x) ENDSWAP_32(x)
+#endif
+
+/*
+ * This should be at least twice as large as the largest number of words
+ * 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).
+ * But to be practical it should be at least 1K bytes.
+ *
+ * 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.  The optimal size
+ * also depends on the CPU cache size and other factors; some twiddling
+ * may be necessary to squeeze out the best performance.
+ */
+static const unsigned FLAC__BITREADER_DEFAULT_CAPACITY = 65536u / FLAC__BITS_PER_WORD; /* in words */
+
+struct FLAC__BitReader {
+	/* any partially-consumed word at the head will stay right-justified as bits are consumed from the left */
+	/* any incomplete word at the tail will be left-justified, and bytes from the read callback are added on the right */
+	uint32_t *buffer;
+	unsigned capacity; /* in words */
+	unsigned words; /* # of completed words in buffer */
+	unsigned bytes; /* # of bytes in incomplete word at buffer[words] */
+	unsigned consumed_words; /* #words ... */
+	unsigned consumed_bits; /* ... + (#bits of head word) already consumed from the front of buffer */
+	unsigned read_crc16; /* the running frame CRC */
+	unsigned crc16_align; /* the number of bits in the current consumed word that should not be CRC'd */
+	FLAC__BitReaderReadCallback read_callback;
+	void *client_data;
+};
+
+static inline void crc16_update_word_(FLAC__BitReader *br, uint32_t word)
+{
+	register unsigned crc = br->read_crc16;
+#if FLAC__BYTES_PER_WORD == 4
+	switch(br->crc16_align) {
+		case  0: crc = FLAC__CRC16_UPDATE((unsigned)(word >> 24), crc);
+		case  8: crc = FLAC__CRC16_UPDATE((unsigned)((word >> 16) & 0xff), crc);
+		case 16: crc = FLAC__CRC16_UPDATE((unsigned)((word >> 8) & 0xff), crc);
+		case 24: br->read_crc16 = FLAC__CRC16_UPDATE((unsigned)(word & 0xff), crc);
+	}
+#elif FLAC__BYTES_PER_WORD == 8
+	switch(br->crc16_align) {
+		case  0: crc = FLAC__CRC16_UPDATE((unsigned)(word >> 56), crc);
+		case  8: crc = FLAC__CRC16_UPDATE((unsigned)((word >> 48) & 0xff), crc);
+		case 16: crc = FLAC__CRC16_UPDATE((unsigned)((word >> 40) & 0xff), crc);
+		case 24: crc = FLAC__CRC16_UPDATE((unsigned)((word >> 32) & 0xff), crc);
+		case 32: crc = FLAC__CRC16_UPDATE((unsigned)((word >> 24) & 0xff), crc);
+		case 40: crc = FLAC__CRC16_UPDATE((unsigned)((word >> 16) & 0xff), crc);
+		case 48: crc = FLAC__CRC16_UPDATE((unsigned)((word >> 8) & 0xff), crc);
+		case 56: br->read_crc16 = FLAC__CRC16_UPDATE((unsigned)(word & 0xff), crc);
+	}
+#else
+	for( ; br->crc16_align < FLAC__BITS_PER_WORD; br->crc16_align += 8)
+		crc = FLAC__CRC16_UPDATE((unsigned)((word >> (FLAC__BITS_PER_WORD-8-br->crc16_align)) & 0xff), crc);
+	br->read_crc16 = crc;
+#endif
+	br->crc16_align = 0;
+}
+
+static FLAC__bool bitreader_read_from_client_(FLAC__BitReader *br)
+{
+	unsigned start, end;
+	size_t bytes;
+	FLAC__byte *target;
+
+	/* first shift the unconsumed buffer data toward the front as much as possible */
+	if(br->consumed_words > 0) {
+		start = br->consumed_words;
+		end = br->words + (br->bytes? 1:0);
+		memmove(br->buffer, br->buffer+start, FLAC__BYTES_PER_WORD * (end - start));
+
+		br->words -= start;
+		br->consumed_words = 0;
+	}
+
+	/*
+	 * set the target for reading, taking into account word alignment and endianness
+	 */
+	bytes = (br->capacity - br->words) * FLAC__BYTES_PER_WORD - br->bytes;
+	if(bytes == 0)
+		return false; /* no space left, buffer is too small; see note for FLAC__BITREADER_DEFAULT_CAPACITY  */
+	target = ((FLAC__byte*)(br->buffer+br->words)) + br->bytes;
+
+	/* before reading, if the existing reader looks like this (say uint32_t is 32 bits wide)
+	 *   bitstream :  11 22 33 44 55            br->words=1 br->bytes=1 (partial tail word is left-justified)
+	 *   buffer[BE]:  11 22 33 44 55 ?? ?? ??   (shown layed out as bytes sequentially in memory)
+	 *   buffer[LE]:  44 33 22 11 ?? ?? ?? 55   (?? being don't-care)
+	 *                               ^^-------target, bytes=3
+	 * on LE machines, have to byteswap the odd tail word so nothing is
+	 * overwritten:
+	 */
+#if WORDS_BIGENDIAN
+#else
+	if(br->bytes)
+		br->buffer[br->words] = SWAP_BE_WORD_TO_HOST(br->buffer[br->words]);
+#endif
+
+	/* now it looks like:
+	 *   bitstream :  11 22 33 44 55            br->words=1 br->bytes=1
+	 *   buffer[BE]:  11 22 33 44 55 ?? ?? ??
+	 *   buffer[LE]:  44 33 22 11 55 ?? ?? ??
+	 *                               ^^-------target, bytes=3
+	 */
+
+	/* read in the data; note that the callback may return a smaller number of bytes */
+	if(!br->read_callback(target, &bytes, br->client_data))
+		return false;
+
+	/* after reading bytes 66 77 88 99 AA BB CC DD EE FF from the client:
+	 *   bitstream :  11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF
+	 *   buffer[BE]:  11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF ??
+	 *   buffer[LE]:  44 33 22 11 55 66 77 88 99 AA BB CC DD EE FF ??
+	 * now have to byteswap on LE machines:
+	 */
+#if WORDS_BIGENDIAN
+#else
+	end = (br->words*FLAC__BYTES_PER_WORD + br->bytes + bytes + (FLAC__BYTES_PER_WORD-1)) / FLAC__BYTES_PER_WORD;
+	for(start = br->words; start < end; start++)
+		br->buffer[start] = SWAP_BE_WORD_TO_HOST(br->buffer[start]);
+#endif
+
+	/* now it looks like:
+	 *   bitstream :  11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF
+	 *   buffer[BE]:  11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF ??
+	 *   buffer[LE]:  44 33 22 11 88 77 66 55 CC BB AA 99 ?? FF EE DD
+	 * finally we'll update the reader values:
+	 */
+	end = br->words*FLAC__BYTES_PER_WORD + br->bytes + bytes;
+	br->words = end / FLAC__BYTES_PER_WORD;
+	br->bytes = end % FLAC__BYTES_PER_WORD;
+
+	return true;
+}
+
+/***********************************************************************
+ *
+ * Class constructor/destructor
+ *
+ ***********************************************************************/
+
+FLAC__BitReader *FLAC__bitreader_new(void)
+{
+	FLAC__BitReader *br = calloc(1, sizeof(FLAC__BitReader));
+
+	/* calloc() implies:
+		memset(br, 0, sizeof(FLAC__BitReader));
+		br->buffer = 0;
+		br->capacity = 0;
+		br->words = br->bytes = 0;
+		br->consumed_words = br->consumed_bits = 0;
+		br->read_callback = 0;
+		br->client_data = 0;
+	*/
+	return br;
+}
+
+void FLAC__bitreader_delete(FLAC__BitReader *br)
+{
+	FLAC__ASSERT(0 != br);
+
+	FLAC__bitreader_free(br);
+	free(br);
+}
+
+/***********************************************************************
+ *
+ * Public class methods
+ *
+ ***********************************************************************/
+
+FLAC__bool FLAC__bitreader_init(FLAC__BitReader *br, FLAC__BitReaderReadCallback rcb, void *cd)
+{
+	FLAC__ASSERT(0 != br);
+
+	br->words = br->bytes = 0;
+	br->consumed_words = br->consumed_bits = 0;
+	br->capacity = FLAC__BITREADER_DEFAULT_CAPACITY;
+	br->buffer = malloc(sizeof(uint32_t) * br->capacity);
+	if(br->buffer == 0)
+		return false;
+	br->read_callback = rcb;
+	br->client_data = cd;
+
+	return true;
+}
+
+void FLAC__bitreader_free(FLAC__BitReader *br)
+{
+	FLAC__ASSERT(0 != br);
+
+	if(0 != br->buffer)
+		free(br->buffer);
+	br->buffer = 0;
+	br->capacity = 0;
+	br->words = br->bytes = 0;
+	br->consumed_words = br->consumed_bits = 0;
+	br->read_callback = 0;
+	br->client_data = 0;
+}
+
+FLAC__bool FLAC__bitreader_clear(FLAC__BitReader *br)
+{
+	br->words = br->bytes = 0;
+	br->consumed_words = br->consumed_bits = 0;
+	return true;
+}
+
+void FLAC__bitreader_dump(const FLAC__BitReader *br, FILE *out)
+{
+	unsigned i, j;
+	if(br == 0) {
+		fprintf(out, "bitreader is NULL\n");
+	}
+	else {
+		fprintf(out, "bitreader: capacity=%u words=%u bytes=%u consumed: words=%u, bits=%u\n", br->capacity, br->words, br->bytes, br->consumed_words, br->consumed_bits);
+
+		for(i = 0; i < br->words; i++) {
+			fprintf(out, "%08X: ", i);
+			for(j = 0; j < FLAC__BITS_PER_WORD; j++)
+				if(i < br->consumed_words || (i == br->consumed_words && j < br->consumed_bits))
+					fprintf(out, ".");
+				else
+					fprintf(out, "%01u", br->buffer[i] & (1 << (FLAC__BITS_PER_WORD-j-1)) ? 1:0);
+			fprintf(out, "\n");
+		}
+		if(br->bytes > 0) {
+			fprintf(out, "%08X: ", i);
+			for(j = 0; j < br->bytes*8; j++)
+				if(i < br->consumed_words || (i == br->consumed_words && j < br->consumed_bits))
+					fprintf(out, ".");
+				else
+					fprintf(out, "%01u", br->buffer[i] & (1 << (br->bytes*8-j-1)) ? 1:0);
+			fprintf(out, "\n");
+		}
+	}
+}
+
+void FLAC__bitreader_reset_read_crc16(FLAC__BitReader *br, FLAC__uint16 seed)
+{
+	FLAC__ASSERT(0 != br);
+	FLAC__ASSERT(0 != br->buffer);
+	FLAC__ASSERT((br->consumed_bits & 7) == 0);
+
+	br->read_crc16 = (unsigned)seed;
+	br->crc16_align = br->consumed_bits;
+}
+
+FLAC__uint16 FLAC__bitreader_get_read_crc16(FLAC__BitReader *br)
+{
+	FLAC__ASSERT(0 != br);
+	FLAC__ASSERT(0 != br->buffer);
+	FLAC__ASSERT((br->consumed_bits & 7) == 0);
+	FLAC__ASSERT(br->crc16_align <= br->consumed_bits);
+
+	/* CRC any tail bytes in a partially-consumed word */
+	if(br->consumed_bits) {
+		const uint32_t tail = br->buffer[br->consumed_words];
+		for( ; br->crc16_align < br->consumed_bits; br->crc16_align += 8)
+			br->read_crc16 = FLAC__CRC16_UPDATE((unsigned)((tail >> (FLAC__BITS_PER_WORD-8-br->crc16_align)) & 0xff), br->read_crc16);
+	}
+	return br->read_crc16;
+}
+
+inline FLAC__bool FLAC__bitreader_is_consumed_byte_aligned(const FLAC__BitReader *br)
+{
+	return ((br->consumed_bits & 7) == 0);
+}
+
+inline unsigned FLAC__bitreader_bits_left_for_byte_alignment(const FLAC__BitReader *br)
+{
+	return 8 - (br->consumed_bits & 7);
+}
+
+inline unsigned FLAC__bitreader_get_input_bits_unconsumed(const FLAC__BitReader *br)
+{
+	return (br->words-br->consumed_words)*FLAC__BITS_PER_WORD + br->bytes*8 - br->consumed_bits;
+}
+
+FLAC__bool FLAC__bitreader_read_raw_uint32(FLAC__BitReader *br, FLAC__uint32 *val, unsigned bits)
+{
+	FLAC__ASSERT(0 != br);
+	FLAC__ASSERT(0 != br->buffer);
+
+	FLAC__ASSERT(bits <= 32);
+	FLAC__ASSERT((br->capacity*FLAC__BITS_PER_WORD) * 2 >= bits);
+	FLAC__ASSERT(br->consumed_words <= br->words);
+
+	/* WATCHOUT: code does not work with <32bit words; we can make things much faster with this assertion */
+	FLAC__ASSERT(FLAC__BITS_PER_WORD >= 32);
+
+	if(bits == 0) { /* OPT: investigate if this can ever happen, maybe change to assertion */
+		*val = 0;
+		return true;
+	}
+
+	while((br->words-br->consumed_words)*FLAC__BITS_PER_WORD + br->bytes*8 - br->consumed_bits < bits) {
+		if(!bitreader_read_from_client_(br))
+			return false;
+	}
+	if(br->consumed_words < br->words) { /* if we've not consumed up to a partial tail word... */
+		/* OPT: taking out the consumed_bits==0 "else" case below might make things faster if less code allows the compiler to inline this function */
+		if(br->consumed_bits) {
+			/* this also works when consumed_bits==0, it's just a little slower than necessary for that case */
+			const unsigned n = FLAC__BITS_PER_WORD - br->consumed_bits;
+			const uint32_t word = br->buffer[br->consumed_words];
+			if(bits < n) {
+				*val = (word & (FLAC__WORD_ALL_ONES >> br->consumed_bits)) >> (n-bits);
+				br->consumed_bits += bits;
+				return true;
+			}
+			*val = word & (FLAC__WORD_ALL_ONES >> br->consumed_bits);
+			bits -= n;
+			crc16_update_word_(br, word);
+			br->consumed_words++;
+			br->consumed_bits = 0;
+			if(bits) { /* if there are still bits left to read, there have to be less than 32 so they will all be in the next word */
+				*val <<= bits;
+				*val |= (br->buffer[br->consumed_words] >> (FLAC__BITS_PER_WORD-bits));
+				br->consumed_bits = bits;
+			}
+			return true;
+		}
+		else {
+			const uint32_t word = br->buffer[br->consumed_words];
+			if(bits < FLAC__BITS_PER_WORD) {
+				*val = word >> (FLAC__BITS_PER_WORD-bits);
+				br->consumed_bits = bits;
+				return true;
+			}
+			/* at this point 'bits' must be == FLAC__BITS_PER_WORD; because of previous assertions, it can't be larger */
+			*val = word;
+			crc16_update_word_(br, word);
+			br->consumed_words++;
+			return true;
+		}
+	}
+	else {
+		/* in this case we're starting our read at a partial tail word;
+		 * the reader has guaranteed that we have at least 'bits' bits
+		 * available to read, which makes this case simpler.
+		 */
+		/* OPT: taking out the consumed_bits==0 "else" case below might make things faster if less code allows the compiler to inline this function */
+		if(br->consumed_bits) {
+			/* this also works when consumed_bits==0, it's just a little slower than necessary for that case */
+			FLAC__ASSERT(br->consumed_bits + bits <= br->bytes*8);
+			*val = (br->buffer[br->consumed_words] & (FLAC__WORD_ALL_ONES >> br->consumed_bits)) >> (FLAC__BITS_PER_WORD-br->consumed_bits-bits);
+			br->consumed_bits += bits;
+			return true;
+		}
+		else {
+			*val = br->buffer[br->consumed_words] >> (FLAC__BITS_PER_WORD-bits);
+			br->consumed_bits += bits;
+			return true;
+		}
+	}
+}
+
+FLAC__bool FLAC__bitreader_read_raw_int32(FLAC__BitReader *br, FLAC__int32 *val, unsigned bits)
+{
+	/* OPT: inline raw uint32 code here, or make into a macro if possible in the .h file */
+	if(!FLAC__bitreader_read_raw_uint32(br, (FLAC__uint32*)val, bits))
+		return false;
+	/* sign-extend: */
+	*val <<= (32-bits);
+	*val >>= (32-bits);
+	return true;
+}
+
+FLAC__bool FLAC__bitreader_read_raw_uint64(FLAC__BitReader *br, FLAC__uint64 *val, unsigned bits)
+{
+	FLAC__uint32 hi, lo;
+
+	if(bits > 32) {
+		if(!FLAC__bitreader_read_raw_uint32(br, &hi, bits-32))
+			return false;
+		if(!FLAC__bitreader_read_raw_uint32(br, &lo, 32))
+			return false;
+		*val = hi;
+		*val <<= 32;
+		*val |= lo;
+	}
+	else {
+		if(!FLAC__bitreader_read_raw_uint32(br, &lo, bits))
+			return false;
+		*val = lo;
+	}
+	return true;
+}
+
+inline FLAC__bool FLAC__bitreader_read_uint32_little_endian(FLAC__BitReader *br, FLAC__uint32 *val)
+{
+	FLAC__uint32 x8, x32 = 0;
+
+	/* this doesn't need to be that fast as currently it is only used for vorbis comments */
+
+	if(!FLAC__bitreader_read_raw_uint32(br, &x32, 8))
+		return false;
+
+	if(!FLAC__bitreader_read_raw_uint32(br, &x8, 8))
+		return false;
+	x32 |= (x8 << 8);
+
+	if(!FLAC__bitreader_read_raw_uint32(br, &x8, 8))
+		return false;
+	x32 |= (x8 << 16);
+
+	if(!FLAC__bitreader_read_raw_uint32(br, &x8, 8))
+		return false;
+	x32 |= (x8 << 24);
+
+	*val = x32;
+	return true;
+}
+
+FLAC__bool FLAC__bitreader_skip_bits_no_crc(FLAC__BitReader *br, unsigned bits)
+{
+	/*
+	 * OPT: a 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 != br);
+	FLAC__ASSERT(0 != br->buffer);
+
+	if(bits > 0) {
+		const unsigned n = br->consumed_bits & 7;
+		unsigned m;
+		FLAC__uint32 x;
+
+		if(n != 0) {
+			m = flac_min(8-n, bits);
+			if(!FLAC__bitreader_read_raw_uint32(br, &x, m))
+				return false;
+			bits -= m;
+		}
+		m = bits / 8;
+		if(m > 0) {
+			if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(br, m))
+				return false;
+			bits %= 8;
+		}
+		if(bits > 0) {
+			if(!FLAC__bitreader_read_raw_uint32(br, &x, bits))
+				return false;
+		}
+	}
+
+	return true;
+}
+
+FLAC__bool FLAC__bitreader_skip_byte_block_aligned_no_crc(FLAC__BitReader *br, unsigned nvals)
+{
+	FLAC__uint32 x;
+
+	FLAC__ASSERT(0 != br);
+	FLAC__ASSERT(0 != br->buffer);
+	FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(br));
+
+	/* step 1: skip over partial head word to get word aligned */
+	while(nvals && br->consumed_bits) { /* i.e. run until we read 'nvals' bytes or we hit the end of the head word */
+		if(!FLAC__bitreader_read_raw_uint32(br, &x, 8))
+			return false;
+		nvals--;
+	}
+	if(0 == nvals)
+		return true;
+	/* step 2: skip whole words in chunks */
+	while(nvals >= FLAC__BYTES_PER_WORD) {
+		if(br->consumed_words < br->words) {
+			br->consumed_words++;
+			nvals -= FLAC__BYTES_PER_WORD;
+		}
+		else if(!bitreader_read_from_client_(br))
+			return false;
+	}
+	/* step 3: skip any remainder from partial tail bytes */
+	while(nvals) {
+		if(!FLAC__bitreader_read_raw_uint32(br, &x, 8))
+			return false;
+		nvals--;
+	}
+
+	return true;
+}
+
+FLAC__bool FLAC__bitreader_read_byte_block_aligned_no_crc(FLAC__BitReader *br, FLAC__byte *val, unsigned nvals)
+{
+	FLAC__uint32 x;
+
+	FLAC__ASSERT(0 != br);
+	FLAC__ASSERT(0 != br->buffer);
+	FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(br));
+
+	/* step 1: read from partial head word to get word aligned */
+	while(nvals && br->consumed_bits) { /* i.e. run until we read 'nvals' bytes or we hit the end of the head word */
+		if(!FLAC__bitreader_read_raw_uint32(br, &x, 8))
+			return false;
+		*val++ = (FLAC__byte)x;
+		nvals--;
+	}
+	if(0 == nvals)
+		return true;
+	/* step 2: read whole words in chunks */
+	while(nvals >= FLAC__BYTES_PER_WORD) {
+		if(br->consumed_words < br->words) {
+			const uint32_t word = br->buffer[br->consumed_words++];
+#if FLAC__BYTES_PER_WORD == 4
+			val[0] = (FLAC__byte)(word >> 24);
+			val[1] = (FLAC__byte)(word >> 16);
+			val[2] = (FLAC__byte)(word >> 8);
+			val[3] = (FLAC__byte)word;
+#elif FLAC__BYTES_PER_WORD == 8
+			val[0] = (FLAC__byte)(word >> 56);
+			val[1] = (FLAC__byte)(word >> 48);
+			val[2] = (FLAC__byte)(word >> 40);
+			val[3] = (FLAC__byte)(word >> 32);
+			val[4] = (FLAC__byte)(word >> 24);
+			val[5] = (FLAC__byte)(word >> 16);
+			val[6] = (FLAC__byte)(word >> 8);
+			val[7] = (FLAC__byte)word;
+#else
+			for(x = 0; x < FLAC__BYTES_PER_WORD; x++)
+				val[x] = (FLAC__byte)(word >> (8*(FLAC__BYTES_PER_WORD-x-1)));
+#endif
+			val += FLAC__BYTES_PER_WORD;
+			nvals -= FLAC__BYTES_PER_WORD;
+		}
+		else if(!bitreader_read_from_client_(br))
+			return false;
+	}
+	/* step 3: read any remainder from partial tail bytes */
+	while(nvals) {
+		if(!FLAC__bitreader_read_raw_uint32(br, &x, 8))
+			return false;
+		*val++ = (FLAC__byte)x;
+		nvals--;
+	}
+
+	return true;
+}
+
+FLAC__bool FLAC__bitreader_read_unary_unsigned(FLAC__BitReader *br, unsigned *val)
+#if 0 /* slow but readable version */
+{
+	unsigned bit;
+
+	FLAC__ASSERT(0 != br);
+	FLAC__ASSERT(0 != br->buffer);
+
+	*val = 0;
+	while(1) {
+		if(!FLAC__bitreader_read_bit(br, &bit))
+			return false;
+		if(bit)
+			break;
+		else
+			*val++;
+	}
+	return true;
+}
+#else
+{
+	unsigned i;
+
+	FLAC__ASSERT(0 != br);
+	FLAC__ASSERT(0 != br->buffer);
+
+	*val = 0;
+	while(1) {
+		while(br->consumed_words < br->words) { /* if we've not consumed up to a partial tail word... */
+			uint32_t b = br->buffer[br->consumed_words] << br->consumed_bits;
+			if(b) {
+				i = FLAC__clz_uint32(b);
+				*val += i;
+				i++;
+				br->consumed_bits += i;
+				if(br->consumed_bits >= FLAC__BITS_PER_WORD) { /* faster way of testing if(br->consumed_bits == FLAC__BITS_PER_WORD) */
+					crc16_update_word_(br, br->buffer[br->consumed_words]);
+					br->consumed_words++;
+					br->consumed_bits = 0;
+				}
+				return true;
+			}
+			else {
+				*val += FLAC__BITS_PER_WORD - br->consumed_bits;
+				crc16_update_word_(br, br->buffer[br->consumed_words]);
+				br->consumed_words++;
+				br->consumed_bits = 0;
+				/* didn't find stop bit yet, have to keep going... */
+			}
+		}
+		/* at this point we've eaten up all the whole words; have to try
+		 * reading through any tail bytes before calling the read callback.
+		 * this is a repeat of the above logic adjusted for the fact we
+		 * don't have a whole word.  note though if the client is feeding
+		 * us data a byte at a time (unlikely), br->consumed_bits may not
+		 * be zero.
+		 */
+		if(br->bytes*8 > br->consumed_bits) {
+			const unsigned end = br->bytes * 8;
+			uint32_t b = (br->buffer[br->consumed_words] & (FLAC__WORD_ALL_ONES << (FLAC__BITS_PER_WORD-end))) << br->consumed_bits;
+			if(b) {
+				i = FLAC__clz_uint32(b);
+				*val += i;
+				i++;
+				br->consumed_bits += i;
+				FLAC__ASSERT(br->consumed_bits < FLAC__BITS_PER_WORD);
+				return true;
+			}
+			else {
+				*val += end - br->consumed_bits;
+				br->consumed_bits = end;
+				FLAC__ASSERT(br->consumed_bits < FLAC__BITS_PER_WORD);
+				/* didn't find stop bit yet, have to keep going... */
+			}
+		}
+		if(!bitreader_read_from_client_(br))
+			return false;
+	}
+}
+#endif
+
+FLAC__bool FLAC__bitreader_read_rice_signed(FLAC__BitReader *br, int *val, unsigned parameter)
+{
+	FLAC__uint32 lsbs = 0, msbs = 0;
+	unsigned uval;
+
+	FLAC__ASSERT(0 != br);
+	FLAC__ASSERT(0 != br->buffer);
+	FLAC__ASSERT(parameter <= 31);
+
+	/* read the unary MSBs and end bit */
+	if(!FLAC__bitreader_read_unary_unsigned(br, &msbs))
+		return false;
+
+	/* read the binary LSBs */
+	if(!FLAC__bitreader_read_raw_uint32(br, &lsbs, parameter))
+		return false;
+
+	/* compose the value */
+	uval = (msbs << parameter) | lsbs;
+	if(uval & 1)
+		*val = -((int)(uval >> 1)) - 1;
+	else
+		*val = (int)(uval >> 1);
+
+	return true;
+}
+
+/* this is by far the most heavily used reader call.  it ain't pretty but it's fast */
+FLAC__bool FLAC__bitreader_read_rice_signed_block(FLAC__BitReader *br, int vals[], unsigned nvals, unsigned parameter)
+{
+	/* try and get br->consumed_words and br->consumed_bits into register;
+	 * must remember to flush them back to *br before calling other
+	 * bitreader functions that use them, and before returning */
+	unsigned cwords, words, lsbs, msbs, x, y;
+	unsigned ucbits; /* keep track of the number of unconsumed bits in word */
+	uint32_t b;
+	int *val, *end;
+
+	FLAC__ASSERT(0 != br);
+	FLAC__ASSERT(0 != br->buffer);
+	/* WATCHOUT: code does not work with <32bit words; we can make things much faster with this assertion */
+	FLAC__ASSERT(FLAC__BITS_PER_WORD >= 32);
+	FLAC__ASSERT(parameter < 32);
+	/* the above two asserts also guarantee that the binary part never straddles more than 2 words, so we don't have to loop to read it */
+
+	val = vals;
+	end = vals + nvals;
+
+	if(parameter == 0) {
+		while(val < end) {
+			/* read the unary MSBs and end bit */
+			if(!FLAC__bitreader_read_unary_unsigned(br, &msbs))
+				return false;
+
+			*val++ = (int)(msbs >> 1) ^ -(int)(msbs & 1);
+		}
+
+		return true;
+	}
+
+	FLAC__ASSERT(parameter > 0);
+
+	cwords = br->consumed_words;
+	words = br->words;
+
+	/* if we've not consumed up to a partial tail word... */
+	if(cwords >= words) {
+		x = 0;
+		goto process_tail;
+	}
+
+	ucbits = FLAC__BITS_PER_WORD - br->consumed_bits;
+	b = br->buffer[cwords] << br->consumed_bits;  /* keep unconsumed bits aligned to left */
+
+	while(val < end) {
+		/* read the unary MSBs and end bit */
+		x = y = FLAC__clz2_uint32(b);
+		if(x == FLAC__BITS_PER_WORD) {
+			x = ucbits;
+			do {
+				/* didn't find stop bit yet, have to keep going... */
+				crc16_update_word_(br, br->buffer[cwords++]);
+				if (cwords >= words)
+					goto incomplete_msbs;
+				b = br->buffer[cwords];
+				y = FLAC__clz2_uint32(b);
+				x += y;
+			} while(y == FLAC__BITS_PER_WORD);
+		}
+		b <<= y;
+		b <<= 1; /* account for stop bit */
+		ucbits = (ucbits - x - 1) % FLAC__BITS_PER_WORD;
+		msbs = x;
+
+		/* read the binary LSBs */
+		x = b >> (FLAC__BITS_PER_WORD - parameter);
+		if(parameter <= ucbits) {
+			ucbits -= parameter;
+			b <<= parameter;
+		} else {
+			/* there are still bits left to read, they will all be in the next word */
+			crc16_update_word_(br, br->buffer[cwords++]);
+			if (cwords >= words)
+				goto incomplete_lsbs;
+			b = br->buffer[cwords];
+			ucbits += FLAC__BITS_PER_WORD - parameter;
+			x |= b >> ucbits;
+			b <<= FLAC__BITS_PER_WORD - ucbits;
+		}
+		lsbs = x;
+
+		/* compose the value */
+		x = (msbs << parameter) | lsbs;
+		*val++ = (int)(x >> 1) ^ -(int)(x & 1);
+
+		continue;
+
+		/* at this point we've eaten up all the whole words */
+process_tail:
+		do {
+			if(0) {
+incomplete_msbs:
+				br->consumed_bits = 0;
+				br->consumed_words = cwords;
+			}
+
+			/* read the unary MSBs and end bit */
+			if(!FLAC__bitreader_read_unary_unsigned(br, &msbs))
+				return false;
+			msbs += x;
+			x = ucbits = 0;
+
+			if(0) {
+incomplete_lsbs:
+				br->consumed_bits = 0;
+				br->consumed_words = cwords;
+			}
+
+			/* read the binary LSBs */
+			if(!FLAC__bitreader_read_raw_uint32(br, &lsbs, parameter - ucbits))
+				return false;
+			lsbs = x | lsbs;
+
+			/* compose the value */
+			x = (msbs << parameter) | lsbs;
+			*val++ = (int)(x >> 1) ^ -(int)(x & 1);
+			x = 0;
+
+			cwords = br->consumed_words;
+			words = br->words;
+			ucbits = FLAC__BITS_PER_WORD - br->consumed_bits;
+			b = br->buffer[cwords] << br->consumed_bits;
+		} while(cwords >= words && val < end);
+	}
+
+	if(ucbits == 0 && cwords < words) {
+		/* don't leave the head word with no unconsumed bits */
+		crc16_update_word_(br, br->buffer[cwords++]);
+		ucbits = FLAC__BITS_PER_WORD;
+	}
+
+	br->consumed_bits = FLAC__BITS_PER_WORD - ucbits;
+	br->consumed_words = cwords;
+
+	return true;
+}
+
+#if 0 /* UNUSED */
+FLAC__bool FLAC__bitreader_read_golomb_signed(FLAC__BitReader *br, int *val, unsigned parameter)
+{
+	FLAC__uint32 lsbs = 0, msbs = 0;
+	unsigned bit, uval, k;
+
+	FLAC__ASSERT(0 != br);
+	FLAC__ASSERT(0 != br->buffer);
+
+	k = FLAC__bitmath_ilog2(parameter);
+
+	/* read the unary MSBs and end bit */
+	if(!FLAC__bitreader_read_unary_unsigned(br, &msbs))
+		return false;
+
+	/* read the binary LSBs */
+	if(!FLAC__bitreader_read_raw_uint32(br, &lsbs, k))
+		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__bitreader_read_bit(br, &bit))
+				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__bitreader_read_golomb_unsigned(FLAC__BitReader *br, unsigned *val, unsigned parameter)
+{
+	FLAC__uint32 lsbs, msbs = 0;
+	unsigned bit, k;
+
+	FLAC__ASSERT(0 != br);
+	FLAC__ASSERT(0 != br->buffer);
+
+	k = FLAC__bitmath_ilog2(parameter);
+
+	/* read the unary MSBs and end bit */
+	if(!FLAC__bitreader_read_unary_unsigned(br, &msbs))
+		return false;
+
+	/* read the binary LSBs */
+	if(!FLAC__bitreader_read_raw_uint32(br, &lsbs, k))
+		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__bitreader_read_bit(br, &bit))
+				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__bitreader_read_utf8_uint32(FLAC__BitReader *br, FLAC__uint32 *val, FLAC__byte *raw, unsigned *rawlen)
+{
+	FLAC__uint32 v = 0;
+	FLAC__uint32 x;
+	unsigned i;
+
+	if(!FLAC__bitreader_read_raw_uint32(br, &x, 8))
+		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__bitreader_read_raw_uint32(br, &x, 8))
+			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__bitreader_read_utf8_uint64(FLAC__BitReader *br, FLAC__uint64 *val, FLAC__byte *raw, unsigned *rawlen)
+{
+	FLAC__uint64 v = 0;
+	FLAC__uint32 x;
+	unsigned i;
+
+	if(!FLAC__bitreader_read_raw_uint32(br, &x, 8))
+		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__bitreader_read_raw_uint32(br, &x, 8))
+			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;
+}
+
+/* These functions are declared inline in this file but are also callable as
+ * externs from elsewhere.
+ * According to the C99 spec, section 6.7.4, simply providing a function
+ * prototype in a header file without 'inline' and making the function inline
+ * in this file should be sufficient.
+ * Unfortunately, the Microsoft VS compiler doesn't pick them up externally. To
+ * fix that we add extern declarations here.
+ */
+extern FLAC__bool FLAC__bitreader_is_consumed_byte_aligned(const FLAC__BitReader *br);
+extern unsigned FLAC__bitreader_bits_left_for_byte_alignment(const FLAC__BitReader *br);
+extern unsigned FLAC__bitreader_get_input_bits_unconsumed(const FLAC__BitReader *br);
+extern FLAC__bool FLAC__bitreader_read_uint32_little_endian(FLAC__BitReader *br, FLAC__uint32 *val);
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/bitwriter.c
@@ -1,0 +1,843 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2014  Xiph.Org Foundation
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include "private/bitwriter.h"
+#include "private/crc.h"
+#include "private/macros.h"
+#include "FLAC/assert.h"
+#include "share/alloc.h"
+#include "share/compat.h"
+#include "share/endswap.h"
+
+/* Things should be fastest when this matches the machine word size */
+/* WATCHOUT: if you change this you must also change the following #defines down to SWAP_BE_WORD_TO_HOST below to match */
+/* WATCHOUT: there are a few places where the code will not work unless uint32_t is >= 32 bits wide */
+#define FLAC__BYTES_PER_WORD 4
+#define FLAC__BITS_PER_WORD 32
+#define FLAC__WORD_ALL_ONES ((FLAC__uint32)0xffffffff)
+/* SWAP_BE_WORD_TO_HOST swaps bytes in a uint32_t (which is always big-endian) if necessary to match host byte order */
+#if WORDS_BIGENDIAN
+#define SWAP_BE_WORD_TO_HOST(x) (x)
+#else
+#define SWAP_BE_WORD_TO_HOST(x) ENDSWAP_32(x)
+#endif
+
+/*
+ * The default capacity here doesn't matter too much.  The buffer always grows
+ * to hold whatever is written to it.  Usually the encoder will stop adding at
+ * a frame or metadata block, then write that out and clear the buffer for the
+ * next one.
+ */
+static const unsigned FLAC__BITWRITER_DEFAULT_CAPACITY = 32768u / sizeof(uint32_t); /* size in words */
+/* When growing, increment 4K at a time */
+static const unsigned FLAC__BITWRITER_DEFAULT_INCREMENT = 4096u / sizeof(uint32_t); /* size in words */
+
+#define FLAC__WORDS_TO_BITS(words) ((words) * FLAC__BITS_PER_WORD)
+#define FLAC__TOTAL_BITS(bw) (FLAC__WORDS_TO_BITS((bw)->words) + (bw)->bits)
+
+struct FLAC__BitWriter {
+	uint32_t *buffer;
+	uint32_t accum; /* accumulator; bits are right-justified; when full, accum is appended to buffer */
+	unsigned capacity; /* capacity of buffer in words */
+	unsigned words; /* # of complete words in buffer */
+	unsigned bits; /* # of used bits in accum */
+};
+
+/* * WATCHOUT: The current implementation only grows the buffer. */
+#ifndef __SUNPRO_C
+static
+#endif
+FLAC__bool bitwriter_grow_(FLAC__BitWriter *bw, unsigned bits_to_add)
+{
+	unsigned new_capacity;
+	uint32_t *new_buffer;
+
+	FLAC__ASSERT(0 != bw);
+	FLAC__ASSERT(0 != bw->buffer);
+
+	/* calculate total words needed to store 'bits_to_add' additional bits */
+	new_capacity = bw->words + ((bw->bits + bits_to_add + FLAC__BITS_PER_WORD - 1) / FLAC__BITS_PER_WORD);
+
+	/* it's possible (due to pessimism in the growth estimation that
+	 * leads to this call) that we don't actually need to grow
+	 */
+	if(bw->capacity >= new_capacity)
+		return true;
+
+	/* round up capacity increase to the nearest FLAC__BITWRITER_DEFAULT_INCREMENT */
+	if((new_capacity - bw->capacity) % FLAC__BITWRITER_DEFAULT_INCREMENT)
+		new_capacity += FLAC__BITWRITER_DEFAULT_INCREMENT - ((new_capacity - bw->capacity) % FLAC__BITWRITER_DEFAULT_INCREMENT);
+	/* make sure we got everything right */
+	FLAC__ASSERT(0 == (new_capacity - bw->capacity) % FLAC__BITWRITER_DEFAULT_INCREMENT);
+	FLAC__ASSERT(new_capacity > bw->capacity);
+	FLAC__ASSERT(new_capacity >= bw->words + ((bw->bits + bits_to_add + FLAC__BITS_PER_WORD - 1) / FLAC__BITS_PER_WORD));
+
+	new_buffer = safe_realloc_mul_2op_(bw->buffer, sizeof(uint32_t), /*times*/new_capacity);
+	if(new_buffer == 0)
+		return false;
+	bw->buffer = new_buffer;
+	bw->capacity = new_capacity;
+	return true;
+}
+
+
+/***********************************************************************
+ *
+ * Class constructor/destructor
+ *
+ ***********************************************************************/
+
+FLAC__BitWriter *FLAC__bitwriter_new(void)
+{
+	FLAC__BitWriter *bw = calloc(1, sizeof(FLAC__BitWriter));
+	/* note that calloc() sets all members to 0 for us */
+	return bw;
+}
+
+void FLAC__bitwriter_delete(FLAC__BitWriter *bw)
+{
+	FLAC__ASSERT(0 != bw);
+
+	FLAC__bitwriter_free(bw);
+	free(bw);
+}
+
+/***********************************************************************
+ *
+ * Public class methods
+ *
+ ***********************************************************************/
+
+FLAC__bool FLAC__bitwriter_init(FLAC__BitWriter *bw)
+{
+	FLAC__ASSERT(0 != bw);
+
+	bw->words = bw->bits = 0;
+	bw->capacity = FLAC__BITWRITER_DEFAULT_CAPACITY;
+	bw->buffer = malloc(sizeof(uint32_t) * bw->capacity);
+	if(bw->buffer == 0)
+		return false;
+
+	return true;
+}
+
+void FLAC__bitwriter_free(FLAC__BitWriter *bw)
+{
+	FLAC__ASSERT(0 != bw);
+
+	if(0 != bw->buffer)
+		free(bw->buffer);
+	bw->buffer = 0;
+	bw->capacity = 0;
+	bw->words = bw->bits = 0;
+}
+
+void FLAC__bitwriter_clear(FLAC__BitWriter *bw)
+{
+	bw->words = bw->bits = 0;
+}
+
+void FLAC__bitwriter_dump(const FLAC__BitWriter *bw, FILE *out)
+{
+	unsigned i, j;
+	if(bw == 0) {
+		fprintf(out, "bitwriter is NULL\n");
+	}
+	else {
+		fprintf(out, "bitwriter: capacity=%u words=%u bits=%u total_bits=%u\n", bw->capacity, bw->words, bw->bits, FLAC__TOTAL_BITS(bw));
+
+		for(i = 0; i < bw->words; i++) {
+			fprintf(out, "%08X: ", i);
+			for(j = 0; j < FLAC__BITS_PER_WORD; j++)
+				fprintf(out, "%01u", bw->buffer[i] & (1 << (FLAC__BITS_PER_WORD-j-1)) ? 1:0);
+			fprintf(out, "\n");
+		}
+		if(bw->bits > 0) {
+			fprintf(out, "%08X: ", i);
+			for(j = 0; j < bw->bits; j++)
+				fprintf(out, "%01u", bw->accum & (1 << (bw->bits-j-1)) ? 1:0);
+			fprintf(out, "\n");
+		}
+	}
+}
+
+FLAC__bool FLAC__bitwriter_get_write_crc16(FLAC__BitWriter *bw, FLAC__uint16 *crc)
+{
+	const FLAC__byte *buffer;
+	size_t bytes;
+
+	FLAC__ASSERT((bw->bits & 7) == 0); /* assert that we're byte-aligned */
+
+	if(!FLAC__bitwriter_get_buffer(bw, &buffer, &bytes))
+		return false;
+
+	*crc = (FLAC__uint16)FLAC__crc16(buffer, bytes);
+	FLAC__bitwriter_release_buffer(bw);
+	return true;
+}
+
+FLAC__bool FLAC__bitwriter_get_write_crc8(FLAC__BitWriter *bw, FLAC__byte *crc)
+{
+	const FLAC__byte *buffer;
+	size_t bytes;
+
+	FLAC__ASSERT((bw->bits & 7) == 0); /* assert that we're byte-aligned */
+
+	if(!FLAC__bitwriter_get_buffer(bw, &buffer, &bytes))
+		return false;
+
+	*crc = FLAC__crc8(buffer, bytes);
+	FLAC__bitwriter_release_buffer(bw);
+	return true;
+}
+
+FLAC__bool FLAC__bitwriter_is_byte_aligned(const FLAC__BitWriter *bw)
+{
+	return ((bw->bits & 7) == 0);
+}
+
+unsigned FLAC__bitwriter_get_input_bits_unconsumed(const FLAC__BitWriter *bw)
+{
+	return FLAC__TOTAL_BITS(bw);
+}
+
+FLAC__bool FLAC__bitwriter_get_buffer(FLAC__BitWriter *bw, const FLAC__byte **buffer, size_t *bytes)
+{
+	FLAC__ASSERT((bw->bits & 7) == 0);
+	/* double protection */
+	if(bw->bits & 7)
+		return false;
+	/* if we have bits in the accumulator we have to flush those to the buffer first */
+	if(bw->bits) {
+		FLAC__ASSERT(bw->words <= bw->capacity);
+		if(bw->words == bw->capacity && !bitwriter_grow_(bw, FLAC__BITS_PER_WORD))
+			return false;
+		/* append bits as complete word to buffer, but don't change bw->accum or bw->bits */
+		bw->buffer[bw->words] = SWAP_BE_WORD_TO_HOST(bw->accum << (FLAC__BITS_PER_WORD-bw->bits));
+	}
+	/* now we can just return what we have */
+	*buffer = (FLAC__byte*)bw->buffer;
+	*bytes = (FLAC__BYTES_PER_WORD * bw->words) + (bw->bits >> 3);
+	return true;
+}
+
+void FLAC__bitwriter_release_buffer(FLAC__BitWriter *bw)
+{
+	/* nothing to do.  in the future, strict checking of a 'writer-is-in-
+	 * get-mode' flag could be added everywhere and then cleared here
+	 */
+	(void)bw;
+}
+
+inline FLAC__bool FLAC__bitwriter_write_zeroes(FLAC__BitWriter *bw, unsigned bits)
+{
+	unsigned n;
+
+	FLAC__ASSERT(0 != bw);
+	FLAC__ASSERT(0 != bw->buffer);
+
+	if(bits == 0)
+		return true;
+	/* slightly pessimistic size check but faster than "<= bw->words + (bw->bits+bits+FLAC__BITS_PER_WORD-1)/FLAC__BITS_PER_WORD" */
+	if(bw->capacity <= bw->words + bits && !bitwriter_grow_(bw, bits))
+		return false;
+	/* first part gets to word alignment */
+	if(bw->bits) {
+		n = flac_min(FLAC__BITS_PER_WORD - bw->bits, bits);
+		bw->accum <<= n;
+		bits -= n;
+		bw->bits += n;
+		if(bw->bits == FLAC__BITS_PER_WORD) {
+			bw->buffer[bw->words++] = SWAP_BE_WORD_TO_HOST(bw->accum);
+			bw->bits = 0;
+		}
+		else
+			return true;
+	}
+	/* do whole words */
+	while(bits >= FLAC__BITS_PER_WORD) {
+		bw->buffer[bw->words++] = 0;
+		bits -= FLAC__BITS_PER_WORD;
+	}
+	/* do any leftovers */
+	if(bits > 0) {
+		bw->accum = 0;
+		bw->bits = bits;
+	}
+	return true;
+}
+
+inline FLAC__bool FLAC__bitwriter_write_raw_uint32(FLAC__BitWriter *bw, FLAC__uint32 val, unsigned bits)
+{
+	register unsigned left;
+
+	/* WATCHOUT: code does not work with <32bit words; we can make things much faster with this assertion */
+	FLAC__ASSERT(FLAC__BITS_PER_WORD >= 32);
+
+	FLAC__ASSERT(0 != bw);
+	FLAC__ASSERT(0 != bw->buffer);
+
+	FLAC__ASSERT(bits <= 32);
+	if(bits == 0)
+		return true;
+
+	/* slightly pessimistic size check but faster than "<= bw->words + (bw->bits+bits+FLAC__BITS_PER_WORD-1)/FLAC__BITS_PER_WORD" */
+	if(bw->capacity <= bw->words + bits && !bitwriter_grow_(bw, bits))
+		return false;
+
+	left = FLAC__BITS_PER_WORD - bw->bits;
+	if(bits < left) {
+		bw->accum <<= bits;
+		bw->accum |= val;
+		bw->bits += bits;
+	}
+	else if(bw->bits) { /* WATCHOUT: if bw->bits == 0, left==FLAC__BITS_PER_WORD and bw->accum<<=left is a NOP instead of setting to 0 */
+		bw->accum <<= left;
+		bw->accum |= val >> (bw->bits = bits - left);
+		bw->buffer[bw->words++] = SWAP_BE_WORD_TO_HOST(bw->accum);
+		bw->accum = val;
+	}
+	else {
+		bw->accum = val;
+		bw->bits = 0;
+		bw->buffer[bw->words++] = SWAP_BE_WORD_TO_HOST(val);
+	}
+
+	return true;
+}
+
+inline FLAC__bool FLAC__bitwriter_write_raw_int32(FLAC__BitWriter *bw, FLAC__int32 val, unsigned bits)
+{
+	/* zero-out unused bits */
+	if(bits < 32)
+		val &= (~(0xffffffff << bits));
+
+	return FLAC__bitwriter_write_raw_uint32(bw, (FLAC__uint32)val, bits);
+}
+
+inline FLAC__bool FLAC__bitwriter_write_raw_uint64(FLAC__BitWriter *bw, FLAC__uint64 val, unsigned bits)
+{
+	/* this could be a little faster but it's not used for much */
+	if(bits > 32) {
+		return
+			FLAC__bitwriter_write_raw_uint32(bw, (FLAC__uint32)(val>>32), bits-32) &&
+			FLAC__bitwriter_write_raw_uint32(bw, (FLAC__uint32)val, 32);
+	}
+	else
+		return FLAC__bitwriter_write_raw_uint32(bw, (FLAC__uint32)val, bits);
+}
+
+inline FLAC__bool FLAC__bitwriter_write_raw_uint32_little_endian(FLAC__BitWriter *bw, FLAC__uint32 val)
+{
+	/* this doesn't need to be that fast as currently it is only used for vorbis comments */
+
+	if(!FLAC__bitwriter_write_raw_uint32(bw, val & 0xff, 8))
+		return false;
+	if(!FLAC__bitwriter_write_raw_uint32(bw, (val>>8) & 0xff, 8))
+		return false;
+	if(!FLAC__bitwriter_write_raw_uint32(bw, (val>>16) & 0xff, 8))
+		return false;
+	if(!FLAC__bitwriter_write_raw_uint32(bw, val>>24, 8))
+		return false;
+
+	return true;
+}
+
+inline FLAC__bool FLAC__bitwriter_write_byte_block(FLAC__BitWriter *bw, const FLAC__byte vals[], unsigned nvals)
+{
+	unsigned i;
+
+	/* this could be faster but currently we don't need it to be since it's only used for writing metadata */
+	for(i = 0; i < nvals; i++) {
+		if(!FLAC__bitwriter_write_raw_uint32(bw, (FLAC__uint32)(vals[i]), 8))
+			return false;
+	}
+
+	return true;
+}
+
+FLAC__bool FLAC__bitwriter_write_unary_unsigned(FLAC__BitWriter *bw, unsigned val)
+{
+	if(val < 32)
+		return FLAC__bitwriter_write_raw_uint32(bw, 1, ++val);
+	else
+		return
+			FLAC__bitwriter_write_zeroes(bw, val) &&
+			FLAC__bitwriter_write_raw_uint32(bw, 1, 1);
+}
+
+unsigned FLAC__bitwriter_rice_bits(FLAC__int32 val, unsigned parameter)
+{
+	FLAC__uint32 uval;
+
+	FLAC__ASSERT(parameter < sizeof(unsigned)*8);
+
+	/* fold signed to unsigned; actual formula is: negative(v)? -2v-1 : 2v */
+	uval = (val<<1) ^ (val>>31);
+
+	return 1 + parameter + (uval >> parameter);
+}
+
+#if 0 /* UNUSED */
+unsigned FLAC__bitwriter_golomb_bits_signed(int val, unsigned parameter)
+{
+	unsigned bits, msbs, uval;
+	unsigned k;
+
+	FLAC__ASSERT(parameter > 0);
+
+	/* fold signed to unsigned */
+	if(val < 0)
+		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__bitwriter_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 */
+
+FLAC__bool FLAC__bitwriter_write_rice_signed(FLAC__BitWriter *bw, FLAC__int32 val, unsigned parameter)
+{
+	unsigned total_bits, interesting_bits, msbs;
+	FLAC__uint32 uval, pattern;
+
+	FLAC__ASSERT(0 != bw);
+	FLAC__ASSERT(0 != bw->buffer);
+	FLAC__ASSERT(parameter < 8*sizeof(uval));
+
+	/* fold signed to unsigned; actual formula is: negative(v)? -2v-1 : 2v */
+	uval = (val<<1) ^ (val>>31);
+
+	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)
+		return FLAC__bitwriter_write_raw_uint32(bw, pattern, total_bits);
+	else
+		return
+			FLAC__bitwriter_write_zeroes(bw, msbs) && /* write the unary MSBs */
+			FLAC__bitwriter_write_raw_uint32(bw, pattern, interesting_bits); /* write the unary end bit and binary LSBs */
+}
+
+FLAC__bool FLAC__bitwriter_write_rice_signed_block(FLAC__BitWriter *bw, const FLAC__int32 *vals, unsigned nvals, unsigned parameter)
+{
+	const FLAC__uint32 mask1 = FLAC__WORD_ALL_ONES << parameter; /* we val|=mask1 to set the stop bit above it... */
+	const FLAC__uint32 mask2 = FLAC__WORD_ALL_ONES >> (31-parameter); /* ...then mask off the bits above the stop bit with val&=mask2*/
+	FLAC__uint32 uval;
+	unsigned left;
+	const unsigned lsbits = 1 + parameter;
+	unsigned msbits;
+
+	FLAC__ASSERT(0 != bw);
+	FLAC__ASSERT(0 != bw->buffer);
+	FLAC__ASSERT(parameter < 8*sizeof(uint32_t)-1);
+	/* WATCHOUT: code does not work with <32bit words; we can make things much faster with this assertion */
+	FLAC__ASSERT(FLAC__BITS_PER_WORD >= 32);
+
+	while(nvals) {
+		/* fold signed to unsigned; actual formula is: negative(v)? -2v-1 : 2v */
+		uval = (*vals<<1) ^ (*vals>>31);
+
+		msbits = uval >> parameter;
+
+		if(bw->bits && bw->bits + msbits + lsbits < FLAC__BITS_PER_WORD) { /* i.e. if the whole thing fits in the current uint32_t */
+			/* ^^^ if bw->bits is 0 then we may have filled the buffer and have no free uint32_t to work in */
+			bw->bits = bw->bits + msbits + lsbits;
+			uval |= mask1; /* set stop bit */
+			uval &= mask2; /* mask off unused top bits */
+			bw->accum <<= msbits + lsbits;
+			bw->accum |= uval;
+		}
+		else {
+			/* slightly pessimistic size check but faster than "<= bw->words + (bw->bits+msbits+lsbits+FLAC__BITS_PER_WORD-1)/FLAC__BITS_PER_WORD" */
+			/* OPT: pessimism may cause flurry of false calls to grow_ which eat up all savings before it */
+			if(bw->capacity <= bw->words + bw->bits + msbits + 1/*lsbits always fit in 1 uint32_t*/ && !bitwriter_grow_(bw, msbits+lsbits))
+				return false;
+
+			if(msbits) {
+				/* first part gets to word alignment */
+				if(bw->bits) {
+					left = FLAC__BITS_PER_WORD - bw->bits;
+					if(msbits < left) {
+						bw->accum <<= msbits;
+						bw->bits += msbits;
+						goto break1;
+					}
+					else {
+						bw->accum <<= left;
+						msbits -= left;
+						bw->buffer[bw->words++] = SWAP_BE_WORD_TO_HOST(bw->accum);
+						bw->bits = 0;
+					}
+				}
+				/* do whole words */
+				while(msbits >= FLAC__BITS_PER_WORD) {
+					bw->buffer[bw->words++] = 0;
+					msbits -= FLAC__BITS_PER_WORD;
+				}
+				/* do any leftovers */
+				if(msbits > 0) {
+					bw->accum = 0;
+					bw->bits = msbits;
+				}
+			}
+break1:
+			uval |= mask1; /* set stop bit */
+			uval &= mask2; /* mask off unused top bits */
+
+			left = FLAC__BITS_PER_WORD - bw->bits;
+			if(lsbits < left) {
+				bw->accum <<= lsbits;
+				bw->accum |= uval;
+				bw->bits += lsbits;
+			}
+			else {
+				/* if bw->bits == 0, left==FLAC__BITS_PER_WORD which will always
+				 * be > lsbits (because of previous assertions) so it would have
+				 * triggered the (lsbits<left) case above.
+				 */
+				FLAC__ASSERT(bw->bits);
+				FLAC__ASSERT(left < FLAC__BITS_PER_WORD);
+				bw->accum <<= left;
+				bw->accum |= uval >> (bw->bits = lsbits - left);
+				bw->buffer[bw->words++] = SWAP_BE_WORD_TO_HOST(bw->accum);
+				bw->accum = uval;
+			}
+		}
+		vals++;
+		nvals--;
+	}
+	return true;
+}
+
+#if 0 /* UNUSED */
+FLAC__bool FLAC__bitwriter_write_golomb_signed(FLAC__BitWriter *bw, int val, unsigned parameter)
+{
+	unsigned total_bits, msbs, uval;
+	unsigned k;
+
+	FLAC__ASSERT(0 != bw);
+	FLAC__ASSERT(0 != bw->buffer);
+	FLAC__ASSERT(parameter > 0);
+
+	/* fold signed to unsigned */
+	if(val < 0)
+		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__bitwriter_write_raw_uint32(bw, pattern, total_bits))
+				return false;
+		}
+		else {
+			/* write the unary MSBs */
+			if(!FLAC__bitwriter_write_zeroes(bw, msbs))
+				return false;
+			/* write the unary end bit and binary LSBs */
+			if(!FLAC__bitwriter_write_raw_uint32(bw, 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__bitwriter_write_zeroes(bw, q))
+			return false;
+		/* write the unary end bit */
+		if(!FLAC__bitwriter_write_raw_uint32(bw, 1, 1))
+			return false;
+		/* write the binary LSBs */
+		if(r >= d) {
+			if(!FLAC__bitwriter_write_raw_uint32(bw, r+d, k+1))
+				return false;
+		}
+		else {
+			if(!FLAC__bitwriter_write_raw_uint32(bw, r, k))
+				return false;
+		}
+	}
+	return true;
+}
+
+FLAC__bool FLAC__bitwriter_write_golomb_unsigned(FLAC__BitWriter *bw, unsigned uval, unsigned parameter)
+{
+	unsigned total_bits, msbs;
+	unsigned k;
+
+	FLAC__ASSERT(0 != bw);
+	FLAC__ASSERT(0 != bw->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__bitwriter_write_raw_uint32(bw, pattern, total_bits))
+				return false;
+		}
+		else {
+			/* write the unary MSBs */
+			if(!FLAC__bitwriter_write_zeroes(bw, msbs))
+				return false;
+			/* write the unary end bit and binary LSBs */
+			if(!FLAC__bitwriter_write_raw_uint32(bw, 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__bitwriter_write_zeroes(bw, q))
+			return false;
+		/* write the unary end bit */
+		if(!FLAC__bitwriter_write_raw_uint32(bw, 1, 1))
+			return false;
+		/* write the binary LSBs */
+		if(r >= d) {
+			if(!FLAC__bitwriter_write_raw_uint32(bw, r+d, k+1))
+				return false;
+		}
+		else {
+			if(!FLAC__bitwriter_write_raw_uint32(bw, r, k))
+				return false;
+		}
+	}
+	return true;
+}
+#endif /* UNUSED */
+
+FLAC__bool FLAC__bitwriter_write_utf8_uint32(FLAC__BitWriter *bw, FLAC__uint32 val)
+{
+	FLAC__bool ok = 1;
+
+	FLAC__ASSERT(0 != bw);
+	FLAC__ASSERT(0 != bw->buffer);
+
+	FLAC__ASSERT(!(val & 0x80000000)); /* this version only handles 31 bits */
+
+	if(val < 0x80) {
+		return FLAC__bitwriter_write_raw_uint32(bw, val, 8);
+	}
+	else if(val < 0x800) {
+		ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xC0 | (val>>6), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (val&0x3F), 8);
+	}
+	else if(val < 0x10000) {
+		ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xE0 | (val>>12), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>6)&0x3F), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (val&0x3F), 8);
+	}
+	else if(val < 0x200000) {
+		ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xF0 | (val>>18), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>12)&0x3F), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>6)&0x3F), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (val&0x3F), 8);
+	}
+	else if(val < 0x4000000) {
+		ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xF8 | (val>>24), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>18)&0x3F), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>12)&0x3F), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>6)&0x3F), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (val&0x3F), 8);
+	}
+	else {
+		ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xFC | (val>>30), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>24)&0x3F), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>18)&0x3F), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>12)&0x3F), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>6)&0x3F), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (val&0x3F), 8);
+	}
+
+	return ok;
+}
+
+FLAC__bool FLAC__bitwriter_write_utf8_uint64(FLAC__BitWriter *bw, FLAC__uint64 val)
+{
+	FLAC__bool ok = 1;
+
+	FLAC__ASSERT(0 != bw);
+	FLAC__ASSERT(0 != bw->buffer);
+
+	FLAC__ASSERT(!(val & FLAC__U64L(0xFFFFFFF000000000))); /* this version only handles 36 bits */
+
+	if(val < 0x80) {
+		return FLAC__bitwriter_write_raw_uint32(bw, (FLAC__uint32)val, 8);
+	}
+	else if(val < 0x800) {
+		ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xC0 | (FLAC__uint32)(val>>6), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8);
+	}
+	else if(val < 0x10000) {
+		ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xE0 | (FLAC__uint32)(val>>12), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8);
+	}
+	else if(val < 0x200000) {
+		ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xF0 | (FLAC__uint32)(val>>18), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>12)&0x3F), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8);
+	}
+	else if(val < 0x4000000) {
+		ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xF8 | (FLAC__uint32)(val>>24), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>18)&0x3F), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>12)&0x3F), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8);
+	}
+	else if(val < 0x80000000) {
+		ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xFC | (FLAC__uint32)(val>>30), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>24)&0x3F), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>18)&0x3F), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>12)&0x3F), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8);
+	}
+	else {
+		ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xFE, 8);
+		ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>30)&0x3F), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>24)&0x3F), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>18)&0x3F), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>12)&0x3F), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8);
+		ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8);
+	}
+
+	return ok;
+}
+
+FLAC__bool FLAC__bitwriter_zero_pad_to_byte_boundary(FLAC__BitWriter *bw)
+{
+	/* 0-pad to byte boundary */
+	if(bw->bits & 7u)
+		return FLAC__bitwriter_write_zeroes(bw, 8 - (bw->bits & 7u));
+	else
+		return true;
+}
+
+/* These functions are declared inline in this file but are also callable as
+ * externs from elsewhere.
+ * According to the C99 spec, section 6.7.4, simply providing a function
+ * prototype in a header file without 'inline' and making the function inline
+ * in this file should be sufficient.
+ * Unfortunately, the Microsoft VS compiler doesn't pick them up externally. To
+ * fix that we add extern declarations here.
+ */
+extern FLAC__bool FLAC__bitwriter_write_zeroes(FLAC__BitWriter *bw, unsigned bits);
+extern FLAC__bool FLAC__bitwriter_write_raw_int32(FLAC__BitWriter *bw, FLAC__int32 val, unsigned bits);
+extern FLAC__bool FLAC__bitwriter_write_raw_uint64(FLAC__BitWriter *bw, FLAC__uint64 val, unsigned bits);
+extern FLAC__bool FLAC__bitwriter_write_raw_uint32_little_endian(FLAC__BitWriter *bw, FLAC__uint32 val);
+extern FLAC__bool FLAC__bitwriter_write_byte_block(FLAC__BitWriter *bw, const FLAC__byte vals[], unsigned nvals);
--- a/sys/src/cmd/audio/libFLAC/cpu.c
+++ b/sys/src/cmd/audio/libFLAC/cpu.c
@@ -1,5 +1,6 @@
 /* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2001,2002,2003,2004  Josh Coalson
+ * Copyright (C) 2001-2009  Josh Coalson
+ * Copyright (C) 2011-2014  Xiph.Org Foundation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -29,89 +30,458 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
 #include "private/cpu.h"
-#include<stdlib.h>
-#include<stdio.h>
+#include "private/memory.h"
+#include <stdlib.h>
+#ifdef DEBUG
+# include <stdio.h>
+#endif
 
-#ifdef HAVE_CONFIG_H
-#include <config.h>
+#if defined FLAC__CPU_IA32
+# include <signal.h>
+
+static void disable_sse(FLAC__CPUInfo *info)
+{
+	info->ia32.sse   = false;
+	info->ia32.sse2  = false;
+	info->ia32.sse3  = false;
+	info->ia32.ssse3 = false;
+	info->ia32.sse41 = false;
+	info->ia32.sse42 = false;
+}
+
+static void disable_avx(FLAC__CPUInfo *info)
+{
+	info->ia32.avx     = false;
+	info->ia32.avx2    = false;
+	info->ia32.fma     = false;
+}
+
+#elif defined FLAC__CPU_X86_64
+
+static void disable_avx(FLAC__CPUInfo *info)
+{
+	info->x86.avx     = false;
+	info->x86.avx2    = false;
+	info->x86.fma     = false;
+}
 #endif
 
-#if defined FLAC__CPU_PPC
-#if !defined FLAC__NO_ASM
-#if defined __APPLE__ && defined __MACH__
+#if defined (__NetBSD__) || defined(__OpenBSD__)
+#include <sys/param.h>
 #include <sys/sysctl.h>
-#endif /* __APPLE__ && __MACH__ */
-#endif /* FLAC__NO_ASM */
-#endif /* FLAC__CPU_PPC */
+#include <machine/cpu.h>
+#endif
 
-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;
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#endif
 
-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;
+#if defined(__APPLE__)
+/* how to get sysctlbyname()? */
+#endif
 
+#ifdef FLAC__CPU_IA32
+/* these are flags in EDX of CPUID AX=00000001 */
+static const unsigned FLAC__CPUINFO_IA32_CPUID_CMOV = 0x00008000;
+static const unsigned FLAC__CPUINFO_IA32_CPUID_MMX = 0x00800000;
+static const unsigned FLAC__CPUINFO_IA32_CPUID_FXSR = 0x01000000;
+static const unsigned FLAC__CPUINFO_IA32_CPUID_SSE = 0x02000000;
+static const unsigned FLAC__CPUINFO_IA32_CPUID_SSE2 = 0x04000000;
+#endif
 
+/* these are flags in ECX of CPUID AX=00000001 */
+static const unsigned FLAC__CPUINFO_IA32_CPUID_SSE3 = 0x00000001;
+static const unsigned FLAC__CPUINFO_IA32_CPUID_SSSE3 = 0x00000200;
+static const unsigned FLAC__CPUINFO_IA32_CPUID_SSE41 = 0x00080000;
+static const unsigned FLAC__CPUINFO_IA32_CPUID_SSE42 = 0x00100000;
+
+#if defined FLAC__AVX_SUPPORTED
+/* these are flags in ECX of CPUID AX=00000001 */
+static const unsigned FLAC__CPUINFO_IA32_CPUID_OSXSAVE = 0x08000000;
+static const unsigned FLAC__CPUINFO_IA32_CPUID_AVX = 0x10000000;
+static const unsigned FLAC__CPUINFO_IA32_CPUID_FMA = 0x00001000;
+/* these are flags in EBX of CPUID AX=00000007 */
+static const unsigned FLAC__CPUINFO_IA32_CPUID_AVX2 = 0x00000020;
+#endif
+
+/*
+ * Extra stuff needed for detection of OS support for SSE on IA-32
+ */
+#if defined(FLAC__CPU_IA32) && !defined FLAC__NO_ASM && (defined FLAC__HAS_NASM || defined FLAC__HAS_X86INTRIN) && !defined FLAC__NO_SSE_OS && !defined FLAC__SSE_OS
+# if defined(__linux__)
+/*
+ * If the OS doesn't support SSE, we will get here with a SIGILL.  We
+ * modify the return address to jump over the offending SSE instruction
+ * and also the operation following it that indicates the instruction
+ * executed successfully.  In this way we use no global variables and
+ * stay thread-safe.
+ *
+ * 3 + 3 + 6:
+ *   3 bytes for "xorps xmm0,xmm0"
+ *   3 bytes for estimate of how long the follwing "inc var" instruction is
+ *   6 bytes extra in case our estimate is wrong
+ * 12 bytes puts us in the NOP "landing zone"
+ */
+#   include <sys/ucontext.h>
+	static void sigill_handler_sse_os(int signal, siginfo_t *si, void *uc)
+	{
+		(void)signal, (void)si;
+		((ucontext_t*)uc)->uc_mcontext.gregs[14/*REG_EIP*/] += 3 + 3 + 6;
+	}
+# elif defined(_MSC_VER)
+#  include <windows.h>
+# endif
+#endif
+
+
 void FLAC__cpu_info(FLAC__CPUInfo *info)
 {
+/*
+ * IA32-specific
+ */
 #ifdef FLAC__CPU_IA32
+	FLAC__bool ia32_fxsr = false;
+	FLAC__bool ia32_osxsave = false;
+	(void) ia32_fxsr; (void) ia32_osxsave; /* to avoid warnings about unused variables */
+	memset(info, 0, sizeof(*info));
 	info->type = FLAC__CPUINFO_TYPE_IA32;
-#if !defined FLAC__NO_ASM && defined FLAC__HAS_NASM
-	info->use_asm = true;
+#if !defined FLAC__NO_ASM && (defined FLAC__HAS_NASM || defined FLAC__HAS_X86INTRIN)
+	info->use_asm = true; /* we assume a minimum of 80386 with FLAC__CPU_IA32 */
+#ifdef FLAC__HAS_X86INTRIN
+	if(!FLAC__cpu_have_cpuid_x86())
+		return;
+#else
+	if(!FLAC__cpu_have_cpuid_asm_ia32())
+		return;
+#endif
 	{
-		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;
+		/* http://www.sandpile.org/x86/cpuid.htm */
+#ifdef FLAC__HAS_X86INTRIN
+		FLAC__uint32 flags_eax, flags_ebx, flags_ecx, flags_edx;
+		FLAC__cpu_info_x86(1, &flags_eax, &flags_ebx, &flags_ecx, &flags_edx);
+#else
+		FLAC__uint32 flags_ecx, flags_edx;
+		FLAC__cpu_info_asm_ia32(&flags_edx, &flags_ecx);
+#endif
+		info->ia32.cmov  = (flags_edx & FLAC__CPUINFO_IA32_CPUID_CMOV )? true : false;
+		info->ia32.mmx   = (flags_edx & FLAC__CPUINFO_IA32_CPUID_MMX  )? true : false;
+		      ia32_fxsr  = (flags_edx & FLAC__CPUINFO_IA32_CPUID_FXSR )? true : false;
+		info->ia32.sse   = (flags_edx & FLAC__CPUINFO_IA32_CPUID_SSE  )? true : false;
+		info->ia32.sse2  = (flags_edx & FLAC__CPUINFO_IA32_CPUID_SSE2 )? true : false;
+		info->ia32.sse3  = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSE3 )? true : false;
+		info->ia32.ssse3 = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSSE3)? true : false;
+		info->ia32.sse41 = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSE41)? true : false;
+		info->ia32.sse42 = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSE42)? true : false;
+#if defined FLAC__HAS_X86INTRIN && defined FLAC__AVX_SUPPORTED
+		    ia32_osxsave = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_OSXSAVE)? true : false;
+		info->ia32.avx   = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_AVX    )? true : false;
+		info->ia32.fma   = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_FMA    )? true : false;
+		FLAC__cpu_info_x86(7, &flags_eax, &flags_ebx, &flags_ecx, &flags_edx);
+		info->ia32.avx2  = (flags_ebx & FLAC__CPUINFO_IA32_CPUID_AVX2   )? true : false;
+#endif
+	}
 
-#ifndef FLAC__SSE_OS
-		info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = false;
+#ifdef DEBUG
+	fprintf(stderr, "CPU info (IA-32):\n");
+	fprintf(stderr, "  CMOV ....... %c\n", info->ia32.cmov    ? 'Y' : 'n');
+	fprintf(stderr, "  MMX ........ %c\n", info->ia32.mmx     ? 'Y' : 'n');
+	fprintf(stderr, "  SSE ........ %c\n", info->ia32.sse     ? 'Y' : 'n');
+	fprintf(stderr, "  SSE2 ....... %c\n", info->ia32.sse2    ? 'Y' : 'n');
+	fprintf(stderr, "  SSE3 ....... %c\n", info->ia32.sse3    ? 'Y' : 'n');
+	fprintf(stderr, "  SSSE3 ...... %c\n", info->ia32.ssse3   ? 'Y' : 'n');
+	fprintf(stderr, "  SSE41 ...... %c\n", info->ia32.sse41   ? 'Y' : 'n');
+	fprintf(stderr, "  SSE42 ...... %c\n", info->ia32.sse42   ? 'Y' : 'n');
+# if defined FLAC__HAS_X86INTRIN && defined FLAC__AVX_SUPPORTED
+	fprintf(stderr, "  AVX ........ %c\n", info->ia32.avx     ? 'Y' : 'n');
+	fprintf(stderr, "  FMA ........ %c\n", info->ia32.fma     ? 'Y' : 'n');
+	fprintf(stderr, "  AVX2 ....... %c\n", info->ia32.avx2    ? 'Y' : 'n');
+# endif
 #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;
+	/*
+	 * now have to check for OS support of SSE instructions
+	 */
+	if(info->ia32.sse) {
+#if defined FLAC__NO_SSE_OS
+		/* assume user knows better than us; turn it off */
+		disable_sse(info);
+#elif defined FLAC__SSE_OS
+		/* assume user knows better than us; leave as detected above */
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) || defined(__APPLE__)
+		int sse = 0;
+		size_t len;
+		/* at least one of these must work: */
+		len = sizeof(sse); sse = sse || (sysctlbyname("hw.instruction_sse", &sse, &len, NULL, 0) == 0 && sse);
+		len = sizeof(sse); sse = sse || (sysctlbyname("hw.optional.sse"   , &sse, &len, NULL, 0) == 0 && sse); /* __APPLE__ ? */
+		if(!sse)
+			disable_sse(info);
+#elif defined(__NetBSD__) || defined (__OpenBSD__)
+# if __NetBSD_Version__ >= 105250000 || (defined __OpenBSD__)
+		int val = 0, mib[2] = { CTL_MACHDEP, CPU_SSE };
+		size_t len = sizeof(val);
+		if(sysctl(mib, 2, &val, &len, NULL, 0) < 0 || !val)
+			disable_sse(info);
+		else { /* double-check SSE2 */
+			mib[1] = CPU_SSE2;
+			len = sizeof(val);
+			if(sysctl(mib, 2, &val, &len, NULL, 0) < 0 || !val) {
+				disable_sse(info);
+				info->ia32.sse = true;
+			}
+		}
+# else
+		disable_sse(info);
+# endif
+#elif defined(__linux__)
+		int sse = 0;
+		struct sigaction sigill_save;
+		struct sigaction sigill_sse;
+		sigill_sse.sa_sigaction = sigill_handler_sse_os;
+		__sigemptyset(&sigill_sse.sa_mask);
+		sigill_sse.sa_flags = SA_SIGINFO | SA_RESETHAND; /* SA_RESETHAND just in case our SIGILL return jump breaks, so we don't get stuck in a loop */
+		if(0 == sigaction(SIGILL, &sigill_sse, &sigill_save))
+		{
+			/* http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html */
+			/* see sigill_handler_sse_os() for an explanation of the following: */
+			asm volatile (
+				"xorps %%xmm0,%%xmm0\n\t" /* will cause SIGILL if unsupported by OS */
+				"incl %0\n\t"             /* SIGILL handler will jump over this */
+				/* landing zone */
+				"nop\n\t" /* SIGILL jump lands here if "inc" is 9 bytes */
+				"nop\n\t"
+				"nop\n\t"
+				"nop\n\t"
+				"nop\n\t"
+				"nop\n\t"
+				"nop\n\t" /* SIGILL jump lands here if "inc" is 3 bytes (expected) */
+				"nop\n\t"
+				"nop"     /* SIGILL jump lands here if "inc" is 1 byte */
+				: "=r"(sse)
+				: "0"(sse)
+			);
+
+			sigaction(SIGILL, &sigill_save, NULL);
+		}
+
+		if(!sse)
+			disable_sse(info);
+#elif defined(_MSC_VER)
+		__try {
+			__asm {
+				xorps xmm0,xmm0
+			}
+		}
+		__except(EXCEPTION_EXECUTE_HANDLER) {
+			if (_exception_code() == STATUS_ILLEGAL_INSTRUCTION)
+				disable_sse(info);
+		}
+#elif defined(__GNUC__) /* MinGW goes here */
+		int sse = 0;
+		/* Based on the idea described in Agner Fog's manual "Optimizing subroutines in assembly language" */
+		/* In theory, not guaranteed to detect lack of OS SSE support on some future Intel CPUs, but in practice works (see the aforementioned manual) */
+		if (ia32_fxsr) {
+			struct {
+				FLAC__uint32 buff[128];
+			} __attribute__((aligned(16))) fxsr;
+			FLAC__uint32 old_val, new_val;
+
+			asm volatile ("fxsave %0"  : "=m" (fxsr) : "m" (fxsr));
+			old_val = fxsr.buff[50];
+			fxsr.buff[50] ^= 0x0013c0de;                             /* change value in the buffer */
+			asm volatile ("fxrstor %0" : "=m" (fxsr) : "m" (fxsr));  /* try to change SSE register */
+			fxsr.buff[50] = old_val;                                 /* restore old value in the buffer */
+			asm volatile ("fxsave %0 " : "=m" (fxsr) : "m" (fxsr));  /* old value will be overwritten if SSE register was changed */
+			new_val = fxsr.buff[50];                                 /* == old_val if FXRSTOR didn't change SSE register and (old_val ^ 0x0013c0de) otherwise */
+			fxsr.buff[50] = old_val;                                 /* again restore old value in the buffer */
+			asm volatile ("fxrstor %0" : "=m" (fxsr) : "m" (fxsr));  /* restore old values of registers */
+
+			if ((old_val^new_val) == 0x0013c0de)
+				sse = 1;
+		}
+		if(!sse)
+			disable_sse(info);
 #else
-		info->data.ia32._3dnow = info->data.ia32.ext3dnow = info->data.ia32.extmmx = false;
+		/* no way to test, disable to be safe */
+		disable_sse(info);
 #endif
+#ifdef DEBUG
+		fprintf(stderr, "  SSE OS sup . %c\n", info->ia32.sse ? 'Y' : 'n');
+#endif
 	}
+	else /* info->ia32.sse == false */
+		disable_sse(info);
+
+	/*
+	 * now have to check for OS support of AVX instructions
+	 */
+	if(info->ia32.avx && ia32_osxsave) {
+		FLAC__uint32 ecr = FLAC__cpu_xgetbv_x86();
+		if ((ecr & 0x6) != 0x6)
+			disable_avx(info);
+#ifdef DEBUG
+		fprintf(stderr, "  AVX OS sup . %c\n", info->ia32.avx ? 'Y' : 'n');
+#endif
+	}
+	else /* no OS AVX support*/
+		disable_avx(info);
 #else
 	info->use_asm = false;
 #endif
-#elif defined FLAC__CPU_PPC
-	info->type = FLAC__CPUINFO_TYPE_PPC;
-#if !defined FLAC__NO_ASM
+
+/*
+ * x86-64-specific
+ */
+#elif defined FLAC__CPU_X86_64
+	FLAC__bool x86_osxsave = false;
+	(void) x86_osxsave; /* to avoid warnings about unused variables */
+	memset(info, 0, sizeof(*info));
+	info->type = FLAC__CPUINFO_TYPE_X86_64;
+#if !defined FLAC__NO_ASM && defined FLAC__HAS_X86INTRIN
 	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);
+		/* http://www.sandpile.org/x86/cpuid.htm */
+		FLAC__uint32 flags_eax, flags_ebx, flags_ecx, flags_edx;
+		FLAC__cpu_info_x86(1, &flags_eax, &flags_ebx, &flags_ecx, &flags_edx);
+		info->x86.sse3  = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSE3 )? true : false;
+		info->x86.ssse3 = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSSE3)? true : false;
+		info->x86.sse41 = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSE41)? true : false;
+		info->x86.sse42 = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSE42)? true : false;
+#if defined FLAC__AVX_SUPPORTED
+		    x86_osxsave = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_OSXSAVE)? true : false;
+		info->x86.avx   = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_AVX    )? true : false;
+		info->x86.fma   = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_FMA    )? true : false;
+		FLAC__cpu_info_x86(7, &flags_eax, &flags_ebx, &flags_ecx, &flags_edx);
+		info->x86.avx2  = (flags_ebx & FLAC__CPUINFO_IA32_CPUID_AVX2   )? true : false;
+#endif
+	}
+#ifdef DEBUG
+	fprintf(stderr, "CPU info (x86-64):\n");
+	fprintf(stderr, "  SSE3 ....... %c\n", info->x86.sse3  ? 'Y' : 'n');
+	fprintf(stderr, "  SSSE3 ...... %c\n", info->x86.ssse3 ? 'Y' : 'n');
+	fprintf(stderr, "  SSE41 ...... %c\n", info->x86.sse41 ? 'Y' : 'n');
+	fprintf(stderr, "  SSE42 ...... %c\n", info->x86.sse42 ? 'Y' : 'n');
+# if defined FLAC__AVX_SUPPORTED
+	fprintf(stderr, "  AVX ........ %c\n", info->x86.avx   ? 'Y' : 'n');
+	fprintf(stderr, "  FMA ........ %c\n", info->x86.fma   ? 'Y' : 'n');
+	fprintf(stderr, "  AVX2 ....... %c\n", info->x86.avx2  ? 'Y' : 'n');
+# endif
+#endif
 
-		info->data.ppc.altivec = error==0 ? result!=0 : 0;
+	/*
+	 * now have to check for OS support of AVX instructions
+	 */
+	if(info->x86.avx && x86_osxsave) {
+		FLAC__uint32 ecr = FLAC__cpu_xgetbv_x86();
+		if ((ecr & 0x6) != 0x6)
+			disable_avx(info);
+#ifdef DEBUG
+		fprintf(stderr, "  AVX OS sup . %c\n", info->x86.avx ? 'Y' : 'n');
+#endif
 	}
-#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 */
+	else /* no OS AVX support*/
+		disable_avx(info);
+#else
 	info->use_asm = false;
-#endif /* FLAC__NO_ASM */
+#endif
+
+/*
+ * unknown CPU
+ */
 #else
 	info->type = FLAC__CPUINFO_TYPE_UNKNOWN;
 	info->use_asm = false;
 #endif
 }
+
+#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && defined FLAC__HAS_X86INTRIN
+
+#if defined _MSC_VER
+#include <intrin.h> /* for __cpuid() and _xgetbv() */
+#elif defined __GNUC__ && defined HAVE_CPUID_H
+#include <cpuid.h> /* for __get_cpuid() and __get_cpuid_max() */
+#endif
+
+FLAC__uint32 FLAC__cpu_have_cpuid_x86(void)
+{
+#ifdef FLAC__CPU_X86_64
+	return 1;
+#else
+# if defined _MSC_VER || defined __INTEL_COMPILER /* Do they support CPUs w/o CPUID support (or OSes that work on those CPUs)? */
+	FLAC__uint32 flags1, flags2;
+	__asm {
+		pushfd
+		pushfd
+		pop		eax
+		mov		flags1, eax
+		xor		eax, 0x200000
+		push	eax
+		popfd
+		pushfd
+		pop		eax
+		mov		flags2, eax
+		popfd
+	}
+	if (((flags1^flags2) & 0x200000) != 0)
+		return 1;
+	else
+		return 0;
+# elif defined __GNUC__ && defined HAVE_CPUID_H
+	if (__get_cpuid_max(0, 0) != 0)
+		return 1;
+	else
+		return 0;
+# else
+	return 0;
+# endif
+#endif
+}
+
+void FLAC__cpu_info_x86(FLAC__uint32 level, FLAC__uint32 *eax, FLAC__uint32 *ebx, FLAC__uint32 *ecx, FLAC__uint32 *edx)
+{
+#if defined _MSC_VER || defined __INTEL_COMPILER
+	int cpuinfo[4];
+	int ext = level & 0x80000000;
+	__cpuid(cpuinfo, ext);
+	if((unsigned)cpuinfo[0] < level) {
+		*eax = *ebx = *ecx = *edx = 0;
+		return;
+	}
+#if defined FLAC__AVX_SUPPORTED
+	__cpuidex(cpuinfo, level, 0); /* for AVX2 detection */
+#else
+	__cpuid(cpuinfo, level); /* some old compilers don't support __cpuidex */
+#endif
+	*eax = cpuinfo[0]; *ebx = cpuinfo[1]; *ecx = cpuinfo[2]; *edx = cpuinfo[3];
+#elif defined __GNUC__ && defined HAVE_CPUID_H
+	FLAC__uint32 ext = level & 0x80000000;
+	__cpuid(ext, *eax, *ebx, *ecx, *edx);
+	if (*eax < level) {
+		*eax = *ebx = *ecx = *edx = 0;
+		return;
+	}
+	__cpuid_count(level, 0, *eax, *ebx, *ecx, *edx);
+#else
+	*eax = *ebx = *ecx = *edx = 0;
+#endif
+}
+
+FLAC__uint32 FLAC__cpu_xgetbv_x86(void)
+{
+#if (defined _MSC_VER || defined __INTEL_COMPILER) && defined FLAC__AVX_SUPPORTED
+	return (FLAC__uint32)_xgetbv(0);
+#elif defined __GNUC__
+	FLAC__uint32 lo, hi;
+	asm volatile (".byte 0x0f, 0x01, 0xd0" : "=a"(lo), "=d"(hi) : "c" (0));
+	return lo;
+#else
+	return 0;
+#endif
+}
+
+#endif /* (FLAC__CPU_IA32 || FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN */
--- a/sys/src/cmd/audio/libFLAC/crc.c
+++ b/sys/src/cmd/audio/libFLAC/crc.c
@@ -1,5 +1,6 @@
 /* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2000,2001,2002,2003,2004  Josh Coalson
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2014  Xiph.Org Foundation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -29,6 +30,10 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
 #include "private/crc.h"
 
 /* CRC-8, poly = x^8 + x^2 + x^1 + x^0, init = 0 */
@@ -70,7 +75,7 @@
 
 /* CRC-16, poly = x^16 + x^15 + x^2 + x^0, init = 0 */
 
-FLAC__uint16 FLAC__crc16_table[256] = {
+unsigned const 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,
@@ -127,23 +132,12 @@
 	return crc;
 }
 
-void FLAC__crc16_update(const FLAC__byte data, FLAC__uint16 *crc)
+unsigned FLAC__crc16(const FLAC__byte *data, unsigned len)
 {
-	*crc = (*crc<<8) ^ FLAC__crc16_table[(*crc>>8) ^ data];
-}
+	unsigned crc = 0;
 
-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++];
+		crc = ((crc<<8) ^ FLAC__crc16_table[(crc>>8) ^ *data++]) & 0xffff;
 
 	return crc;
 }
--- a/sys/src/cmd/audio/libFLAC/file_decoder.c
+++ /dev/null
@@ -1,675 +1,0 @@
-/* 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_(void);
-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"
-};
-
-FLAC_API FLAC__SeekableStreamDecoder *FLAC__seekable_stream_decoder_new(void);
-
-/***********************************************************************
- *
- * Class constructor/destructor
- *
- ***********************************************************************/
-
-FLAC_API FLAC__FileDecoder *FLAC__file_decoder_new(void)
-{
-	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_(void)
-{
-	/* 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);
-}
--- a/sys/src/cmd/audio/libFLAC/file_encoder.c
+++ /dev/null
@@ -1,777 +1,0 @@
-/* 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"
-};
-
-FLAC_API FLAC__SeekableStreamEncoder *FLAC__seekable_stream_encoder_new(void);
-
-/***********************************************************************
- *
- * 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;
-}
--- a/sys/src/cmd/audio/libFLAC/fixed.c
+++ b/sys/src/cmd/audio/libFLAC/fixed.c
@@ -1,5 +1,6 @@
 /* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2000,2001,2002,2003,2004  Josh Coalson
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2014  Xiph.Org Foundation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -29,27 +30,195 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
 #include <math.h>
+#include <string.h>
+#include "share/compat.h"
+#include "private/bitmath.h"
 #include "private/fixed.h"
+#include "private/macros.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])
+#ifdef FLAC__INTEGER_ONLY_LIBRARY
+/* rbps stands for residual bits per sample
+ *
+ *             (ln(2) * err)
+ * rbps = log  (-----------)
+ *           2 (     n     )
+ */
+static FLAC__fixedpoint local__compute_rbps_integerized(FLAC__uint32 err, FLAC__uint32 n)
 {
+	FLAC__uint32 rbps;
+	unsigned bits; /* the number of bits required to represent a number */
+	int fracbits; /* the number of bits of rbps that comprise the fractional part */
+
+	FLAC__ASSERT(sizeof(rbps) == sizeof(FLAC__fixedpoint));
+	FLAC__ASSERT(err > 0);
+	FLAC__ASSERT(n > 0);
+
+	FLAC__ASSERT(n <= FLAC__MAX_BLOCK_SIZE);
+	if(err <= n)
+		return 0;
+	/*
+	 * The above two things tell us 1) n fits in 16 bits; 2) err/n > 1.
+	 * These allow us later to know we won't lose too much precision in the
+	 * fixed-point division (err<<fracbits)/n.
+	 */
+
+	fracbits = (8*sizeof(err)) - (FLAC__bitmath_ilog2(err)+1);
+
+	err <<= fracbits;
+	err /= n;
+	/* err now holds err/n with fracbits fractional bits */
+
+	/*
+	 * Whittle err down to 16 bits max.  16 significant bits is enough for
+	 * our purposes.
+	 */
+	FLAC__ASSERT(err > 0);
+	bits = FLAC__bitmath_ilog2(err)+1;
+	if(bits > 16) {
+		err >>= (bits-16);
+		fracbits -= (bits-16);
+	}
+	rbps = (FLAC__uint32)err;
+
+	/* Multiply by fixed-point version of ln(2), with 16 fractional bits */
+	rbps *= FLAC__FP_LN2;
+	fracbits += 16;
+	FLAC__ASSERT(fracbits >= 0);
+
+	/* FLAC__fixedpoint_log2 requires fracbits%4 to be 0 */
+	{
+		const int f = fracbits & 3;
+		if(f) {
+			rbps >>= f;
+			fracbits -= f;
+		}
+	}
+
+	rbps = FLAC__fixedpoint_log2(rbps, fracbits, (unsigned)(-1));
+
+	if(rbps == 0)
+		return 0;
+
+	/*
+	 * The return value must have 16 fractional bits.  Since the whole part
+	 * of the base-2 log of a 32 bit number must fit in 5 bits, and fracbits
+	 * must be >= -3, these assertion allows us to be able to shift rbps
+	 * left if necessary to get 16 fracbits without losing any bits of the
+	 * whole part of rbps.
+	 *
+	 * There is a slight chance due to accumulated error that the whole part
+	 * will require 6 bits, so we use 6 in the assertion.  Really though as
+	 * long as it fits in 13 bits (32 - (16 - (-3))) we are fine.
+	 */
+	FLAC__ASSERT((int)FLAC__bitmath_ilog2(rbps)+1 <= fracbits + 6);
+	FLAC__ASSERT(fracbits >= -3);
+
+	/* now shift the decimal point into place */
+	if(fracbits < 16)
+		return rbps << (16-fracbits);
+	else if(fracbits > 16)
+		return rbps >> (fracbits-16);
+	else
+		return rbps;
+}
+
+static FLAC__fixedpoint local__compute_rbps_wide_integerized(FLAC__uint64 err, FLAC__uint32 n)
+{
+	FLAC__uint32 rbps;
+	unsigned bits; /* the number of bits required to represent a number */
+	int fracbits; /* the number of bits of rbps that comprise the fractional part */
+
+	FLAC__ASSERT(sizeof(rbps) == sizeof(FLAC__fixedpoint));
+	FLAC__ASSERT(err > 0);
+	FLAC__ASSERT(n > 0);
+
+	FLAC__ASSERT(n <= FLAC__MAX_BLOCK_SIZE);
+	if(err <= n)
+		return 0;
+	/*
+	 * The above two things tell us 1) n fits in 16 bits; 2) err/n > 1.
+	 * These allow us later to know we won't lose too much precision in the
+	 * fixed-point division (err<<fracbits)/n.
+	 */
+
+	fracbits = (8*sizeof(err)) - (FLAC__bitmath_ilog2_wide(err)+1);
+
+	err <<= fracbits;
+	err /= n;
+	/* err now holds err/n with fracbits fractional bits */
+
+	/*
+	 * Whittle err down to 16 bits max.  16 significant bits is enough for
+	 * our purposes.
+	 */
+	FLAC__ASSERT(err > 0);
+	bits = FLAC__bitmath_ilog2_wide(err)+1;
+	if(bits > 16) {
+		err >>= (bits-16);
+		fracbits -= (bits-16);
+	}
+	rbps = (FLAC__uint32)err;
+
+	/* Multiply by fixed-point version of ln(2), with 16 fractional bits */
+	rbps *= FLAC__FP_LN2;
+	fracbits += 16;
+	FLAC__ASSERT(fracbits >= 0);
+
+	/* FLAC__fixedpoint_log2 requires fracbits%4 to be 0 */
+	{
+		const int f = fracbits & 3;
+		if(f) {
+			rbps >>= f;
+			fracbits -= f;
+		}
+	}
+
+	rbps = FLAC__fixedpoint_log2(rbps, fracbits, (unsigned)(-1));
+
+	if(rbps == 0)
+		return 0;
+
+	/*
+	 * The return value must have 16 fractional bits.  Since the whole part
+	 * of the base-2 log of a 32 bit number must fit in 5 bits, and fracbits
+	 * must be >= -3, these assertion allows us to be able to shift rbps
+	 * left if necessary to get 16 fracbits without losing any bits of the
+	 * whole part of rbps.
+	 *
+	 * There is a slight chance due to accumulated error that the whole part
+	 * will require 6 bits, so we use 6 in the assertion.  Really though as
+	 * long as it fits in 13 bits (32 - (16 - (-3))) we are fine.
+	 */
+	FLAC__ASSERT((int)FLAC__bitmath_ilog2(rbps)+1 <= fracbits + 6);
+	FLAC__ASSERT(fracbits >= -3);
+
+	/* now shift the decimal point into place */
+	if(fracbits < 16)
+		return rbps << (16-fracbits);
+	else if(fracbits > 16)
+		return rbps >> (fracbits-16);
+	else
+		return rbps;
+}
+#endif
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+unsigned FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1])
+#else
+unsigned FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], unsigned data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1])
+#endif
+{
 	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]);
@@ -66,11 +235,11 @@
 		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))
+	if(total_error_0 < flac_min(flac_min(flac_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))
+	else if(total_error_1 < flac_min(flac_min(total_error_2, total_error_3), total_error_4))
 		order = 1;
-	else if(total_error_2 < min(total_error_3, total_error_4))
+	else if(total_error_2 < flac_min(total_error_3, total_error_4))
 		order = 2;
 	else if(total_error_3 < total_error_4)
 		order = 3;
@@ -85,16 +254,28 @@
 	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);
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+	residual_bits_per_sample[0] = (FLAC__float)((total_error_0 > 0) ? log(M_LN2 * (FLAC__double)total_error_0 / (FLAC__double)data_len) / M_LN2 : 0.0);
+	residual_bits_per_sample[1] = (FLAC__float)((total_error_1 > 0) ? log(M_LN2 * (FLAC__double)total_error_1 / (FLAC__double)data_len) / M_LN2 : 0.0);
+	residual_bits_per_sample[2] = (FLAC__float)((total_error_2 > 0) ? log(M_LN2 * (FLAC__double)total_error_2 / (FLAC__double)data_len) / M_LN2 : 0.0);
+	residual_bits_per_sample[3] = (FLAC__float)((total_error_3 > 0) ? log(M_LN2 * (FLAC__double)total_error_3 / (FLAC__double)data_len) / M_LN2 : 0.0);
+	residual_bits_per_sample[4] = (FLAC__float)((total_error_4 > 0) ? log(M_LN2 * (FLAC__double)total_error_4 / (FLAC__double)data_len) / M_LN2 : 0.0);
+#else
+	residual_bits_per_sample[0] = (total_error_0 > 0) ? local__compute_rbps_integerized(total_error_0, data_len) : 0;
+	residual_bits_per_sample[1] = (total_error_1 > 0) ? local__compute_rbps_integerized(total_error_1, data_len) : 0;
+	residual_bits_per_sample[2] = (total_error_2 > 0) ? local__compute_rbps_integerized(total_error_2, data_len) : 0;
+	residual_bits_per_sample[3] = (total_error_3 > 0) ? local__compute_rbps_integerized(total_error_3, data_len) : 0;
+	residual_bits_per_sample[4] = (total_error_4 > 0) ? local__compute_rbps_integerized(total_error_4, data_len) : 0;
+#endif
 
 	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])
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+unsigned FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1])
+#else
+unsigned FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], unsigned data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1])
+#endif
 {
 	FLAC__int32 last_error_0 = data[-1];
 	FLAC__int32 last_error_1 = data[-1] - data[-2];
@@ -116,11 +297,11 @@
 		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))
+	if(total_error_0 < flac_min(flac_min(flac_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))
+	else if(total_error_1 < flac_min(flac_min(total_error_2, total_error_3), total_error_4))
 		order = 1;
-	else if(total_error_2 < min(total_error_3, total_error_4))
+	else if(total_error_2 < flac_min(total_error_3, total_error_4))
 		order = 2;
 	else if(total_error_3 < total_error_4)
 		order = 3;
@@ -135,19 +316,18 @@
 	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);
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+	residual_bits_per_sample[0] = (FLAC__float)((total_error_0 > 0) ? log(M_LN2 * (FLAC__double)total_error_0 / (FLAC__double)data_len) / M_LN2 : 0.0);
+	residual_bits_per_sample[1] = (FLAC__float)((total_error_1 > 0) ? log(M_LN2 * (FLAC__double)total_error_1 / (FLAC__double)data_len) / M_LN2 : 0.0);
+	residual_bits_per_sample[2] = (FLAC__float)((total_error_2 > 0) ? log(M_LN2 * (FLAC__double)total_error_2 / (FLAC__double)data_len) / M_LN2 : 0.0);
+	residual_bits_per_sample[3] = (FLAC__float)((total_error_3 > 0) ? log(M_LN2 * (FLAC__double)total_error_3 / (FLAC__double)data_len) / M_LN2 : 0.0);
+	residual_bits_per_sample[4] = (FLAC__float)((total_error_4 > 0) ? log(M_LN2 * (FLAC__double)total_error_4 / (FLAC__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);
+	residual_bits_per_sample[0] = (total_error_0 > 0) ? local__compute_rbps_wide_integerized(total_error_0, data_len) : 0;
+	residual_bits_per_sample[1] = (total_error_1 > 0) ? local__compute_rbps_wide_integerized(total_error_1, data_len) : 0;
+	residual_bits_per_sample[2] = (total_error_2 > 0) ? local__compute_rbps_wide_integerized(total_error_2, data_len) : 0;
+	residual_bits_per_sample[3] = (total_error_3 > 0) ? local__compute_rbps_wide_integerized(total_error_3, data_len) : 0;
+	residual_bits_per_sample[4] = (total_error_4 > 0) ? local__compute_rbps_wide_integerized(total_error_4, data_len) : 0;
 #endif
 
 	return order;
@@ -160,32 +340,36 @@
 
 	switch(order) {
 		case 0:
-			for(i = 0; i < idata_len; i++) {
-				residual[i] = data[i];
-			}
+			FLAC__ASSERT(sizeof(residual[0]) == sizeof(data[0]));
+			memcpy(residual, data, sizeof(residual[0])*data_len);
 			break;
 		case 1:
-			for(i = 0; i < idata_len; i++) {
+			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] */
+			for(i = 0; i < idata_len; i++)
+#if 1 /* OPT: may be faster with some compilers on some systems */
 				residual[i] = data[i] - (data[i-1] << 1) + data[i-2];
-			}
+#else
+				residual[i] = data[i] - 2*data[i-1] + data[i-2];
+#endif
 			break;
 		case 3:
-			for(i = 0; i < idata_len; i++) {
-				/* == data[i] - 3*data[i-1] + 3*data[i-2] - data[i-3] */
+			for(i = 0; i < idata_len; i++)
+#if 1 /* OPT: may be faster with some compilers on some systems */
 				residual[i] = data[i] - (((data[i-1]-data[i-2])<<1) + (data[i-1]-data[i-2])) - data[i-3];
-			}
+#else
+				residual[i] = data[i] - 3*data[i-1] + 3*data[i-2] - data[i-3];
+#endif
 			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] */
+			for(i = 0; i < idata_len; i++)
+#if 1 /* OPT: may be faster with some compilers on some systems */
 				residual[i] = data[i] - ((data[i-1]+data[i-3])<<2) + ((data[i-2]<<2) + (data[i-2]<<1)) + data[i-4];
-			}
+#else
+				residual[i] = data[i] - 4*data[i-1] + 6*data[i-2] - 4*data[i-3] + data[i-4];
+#endif
 			break;
 		default:
 			FLAC__ASSERT(0);
@@ -198,32 +382,36 @@
 
 	switch(order) {
 		case 0:
-			for(i = 0; i < idata_len; i++) {
-				data[i] = residual[i];
-			}
+			FLAC__ASSERT(sizeof(residual[0]) == sizeof(data[0]));
+			memcpy(data, residual, sizeof(residual[0])*data_len);
 			break;
 		case 1:
-			for(i = 0; i < idata_len; i++) {
+			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] */
+			for(i = 0; i < idata_len; i++)
+#if 1 /* OPT: may be faster with some compilers on some systems */
 				data[i] = residual[i] + (data[i-1]<<1) - data[i-2];
-			}
+#else
+				data[i] = residual[i] + 2*data[i-1] - data[i-2];
+#endif
 			break;
 		case 3:
-			for(i = 0; i < idata_len; i++) {
-				/* residual[i] + 3*data[i-1] - 3*data[i-2]) + data[i-3] */
+			for(i = 0; i < idata_len; i++)
+#if 1 /* OPT: may be faster with some compilers on some systems */
 				data[i] = residual[i] + (((data[i-1]-data[i-2])<<1) + (data[i-1]-data[i-2])) + data[i-3];
-			}
+#else
+				data[i] = residual[i] + 3*data[i-1] - 3*data[i-2] + data[i-3];
+#endif
 			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] */
+			for(i = 0; i < idata_len; i++)
+#if 1 /* OPT: may be faster with some compilers on some systems */
 				data[i] = residual[i] + ((data[i-1]+data[i-3])<<2) - ((data[i-2]<<2) + (data[i-2]<<1)) - data[i-4];
-			}
+#else
+				data[i] = residual[i] + 4*data[i-1] - 6*data[i-2] + 4*data[i-3] - data[i-4];
+#endif
 			break;
 		default:
 			FLAC__ASSERT(0);
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/float.c
@@ -1,0 +1,302 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2004-2009  Josh Coalson
+ * Copyright (C) 2011-2014  Xiph.Org Foundation
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "FLAC/assert.h"
+#include "share/compat.h"
+#include "private/float.h"
+
+#ifdef FLAC__INTEGER_ONLY_LIBRARY
+
+const FLAC__fixedpoint FLAC__FP_ZERO = 0;
+const FLAC__fixedpoint FLAC__FP_ONE_HALF = 0x00008000;
+const FLAC__fixedpoint FLAC__FP_ONE = 0x00010000;
+const FLAC__fixedpoint FLAC__FP_LN2 = 45426;
+const FLAC__fixedpoint FLAC__FP_E = 178145;
+
+/* Lookup tables for Knuth's logarithm algorithm */
+#define LOG2_LOOKUP_PRECISION 16
+static const FLAC__uint32 log2_lookup[][LOG2_LOOKUP_PRECISION] = {
+	{
+		/*
+		 * 0 fraction bits
+		 */
+		/* undefined */ 0x00000000,
+		/* lg(2/1) = */ 0x00000001,
+		/* lg(4/3) = */ 0x00000000,
+		/* lg(8/7) = */ 0x00000000,
+		/* lg(16/15) = */ 0x00000000,
+		/* lg(32/31) = */ 0x00000000,
+		/* lg(64/63) = */ 0x00000000,
+		/* lg(128/127) = */ 0x00000000,
+		/* lg(256/255) = */ 0x00000000,
+		/* lg(512/511) = */ 0x00000000,
+		/* lg(1024/1023) = */ 0x00000000,
+		/* lg(2048/2047) = */ 0x00000000,
+		/* lg(4096/4095) = */ 0x00000000,
+		/* lg(8192/8191) = */ 0x00000000,
+		/* lg(16384/16383) = */ 0x00000000,
+		/* lg(32768/32767) = */ 0x00000000
+	},
+	{
+		/*
+		 * 4 fraction bits
+		 */
+		/* undefined */ 0x00000000,
+		/* lg(2/1) = */ 0x00000010,
+		/* lg(4/3) = */ 0x00000007,
+		/* lg(8/7) = */ 0x00000003,
+		/* lg(16/15) = */ 0x00000001,
+		/* lg(32/31) = */ 0x00000001,
+		/* lg(64/63) = */ 0x00000000,
+		/* lg(128/127) = */ 0x00000000,
+		/* lg(256/255) = */ 0x00000000,
+		/* lg(512/511) = */ 0x00000000,
+		/* lg(1024/1023) = */ 0x00000000,
+		/* lg(2048/2047) = */ 0x00000000,
+		/* lg(4096/4095) = */ 0x00000000,
+		/* lg(8192/8191) = */ 0x00000000,
+		/* lg(16384/16383) = */ 0x00000000,
+		/* lg(32768/32767) = */ 0x00000000
+	},
+	{
+		/*
+		 * 8 fraction bits
+		 */
+		/* undefined */ 0x00000000,
+		/* lg(2/1) = */ 0x00000100,
+		/* lg(4/3) = */ 0x0000006a,
+		/* lg(8/7) = */ 0x00000031,
+		/* lg(16/15) = */ 0x00000018,
+		/* lg(32/31) = */ 0x0000000c,
+		/* lg(64/63) = */ 0x00000006,
+		/* lg(128/127) = */ 0x00000003,
+		/* lg(256/255) = */ 0x00000001,
+		/* lg(512/511) = */ 0x00000001,
+		/* lg(1024/1023) = */ 0x00000000,
+		/* lg(2048/2047) = */ 0x00000000,
+		/* lg(4096/4095) = */ 0x00000000,
+		/* lg(8192/8191) = */ 0x00000000,
+		/* lg(16384/16383) = */ 0x00000000,
+		/* lg(32768/32767) = */ 0x00000000
+	},
+	{
+		/*
+		 * 12 fraction bits
+		 */
+		/* undefined */ 0x00000000,
+		/* lg(2/1) = */ 0x00001000,
+		/* lg(4/3) = */ 0x000006a4,
+		/* lg(8/7) = */ 0x00000315,
+		/* lg(16/15) = */ 0x0000017d,
+		/* lg(32/31) = */ 0x000000bc,
+		/* lg(64/63) = */ 0x0000005d,
+		/* lg(128/127) = */ 0x0000002e,
+		/* lg(256/255) = */ 0x00000017,
+		/* lg(512/511) = */ 0x0000000c,
+		/* lg(1024/1023) = */ 0x00000006,
+		/* lg(2048/2047) = */ 0x00000003,
+		/* lg(4096/4095) = */ 0x00000001,
+		/* lg(8192/8191) = */ 0x00000001,
+		/* lg(16384/16383) = */ 0x00000000,
+		/* lg(32768/32767) = */ 0x00000000
+	},
+	{
+		/*
+		 * 16 fraction bits
+		 */
+		/* undefined */ 0x00000000,
+		/* lg(2/1) = */ 0x00010000,
+		/* lg(4/3) = */ 0x00006a40,
+		/* lg(8/7) = */ 0x00003151,
+		/* lg(16/15) = */ 0x000017d6,
+		/* lg(32/31) = */ 0x00000bba,
+		/* lg(64/63) = */ 0x000005d1,
+		/* lg(128/127) = */ 0x000002e6,
+		/* lg(256/255) = */ 0x00000172,
+		/* lg(512/511) = */ 0x000000b9,
+		/* lg(1024/1023) = */ 0x0000005c,
+		/* lg(2048/2047) = */ 0x0000002e,
+		/* lg(4096/4095) = */ 0x00000017,
+		/* lg(8192/8191) = */ 0x0000000c,
+		/* lg(16384/16383) = */ 0x00000006,
+		/* lg(32768/32767) = */ 0x00000003
+	},
+	{
+		/*
+		 * 20 fraction bits
+		 */
+		/* undefined */ 0x00000000,
+		/* lg(2/1) = */ 0x00100000,
+		/* lg(4/3) = */ 0x0006a3fe,
+		/* lg(8/7) = */ 0x00031513,
+		/* lg(16/15) = */ 0x00017d60,
+		/* lg(32/31) = */ 0x0000bb9d,
+		/* lg(64/63) = */ 0x00005d10,
+		/* lg(128/127) = */ 0x00002e59,
+		/* lg(256/255) = */ 0x00001721,
+		/* lg(512/511) = */ 0x00000b8e,
+		/* lg(1024/1023) = */ 0x000005c6,
+		/* lg(2048/2047) = */ 0x000002e3,
+		/* lg(4096/4095) = */ 0x00000171,
+		/* lg(8192/8191) = */ 0x000000b9,
+		/* lg(16384/16383) = */ 0x0000005c,
+		/* lg(32768/32767) = */ 0x0000002e
+	},
+	{
+		/*
+		 * 24 fraction bits
+		 */
+		/* undefined */ 0x00000000,
+		/* lg(2/1) = */ 0x01000000,
+		/* lg(4/3) = */ 0x006a3fe6,
+		/* lg(8/7) = */ 0x00315130,
+		/* lg(16/15) = */ 0x0017d605,
+		/* lg(32/31) = */ 0x000bb9ca,
+		/* lg(64/63) = */ 0x0005d0fc,
+		/* lg(128/127) = */ 0x0002e58f,
+		/* lg(256/255) = */ 0x0001720e,
+		/* lg(512/511) = */ 0x0000b8d8,
+		/* lg(1024/1023) = */ 0x00005c61,
+		/* lg(2048/2047) = */ 0x00002e2d,
+		/* lg(4096/4095) = */ 0x00001716,
+		/* lg(8192/8191) = */ 0x00000b8b,
+		/* lg(16384/16383) = */ 0x000005c5,
+		/* lg(32768/32767) = */ 0x000002e3
+	},
+	{
+		/*
+		 * 28 fraction bits
+		 */
+		/* undefined */ 0x00000000,
+		/* lg(2/1) = */ 0x10000000,
+		/* lg(4/3) = */ 0x06a3fe5c,
+		/* lg(8/7) = */ 0x03151301,
+		/* lg(16/15) = */ 0x017d6049,
+		/* lg(32/31) = */ 0x00bb9ca6,
+		/* lg(64/63) = */ 0x005d0fba,
+		/* lg(128/127) = */ 0x002e58f7,
+		/* lg(256/255) = */ 0x001720da,
+		/* lg(512/511) = */ 0x000b8d87,
+		/* lg(1024/1023) = */ 0x0005c60b,
+		/* lg(2048/2047) = */ 0x0002e2d7,
+		/* lg(4096/4095) = */ 0x00017160,
+		/* lg(8192/8191) = */ 0x0000b8ad,
+		/* lg(16384/16383) = */ 0x00005c56,
+		/* lg(32768/32767) = */ 0x00002e2b
+	}
+};
+
+#if 0
+static const FLAC__uint64 log2_lookup_wide[] = {
+	{
+		/*
+		 * 32 fraction bits
+		 */
+		/* undefined */ 0x00000000,
+		/* lg(2/1) = */ FLAC__U64L(0x100000000),
+		/* lg(4/3) = */ FLAC__U64L(0x6a3fe5c6),
+		/* lg(8/7) = */ FLAC__U64L(0x31513015),
+		/* lg(16/15) = */ FLAC__U64L(0x17d60497),
+		/* lg(32/31) = */ FLAC__U64L(0x0bb9ca65),
+		/* lg(64/63) = */ FLAC__U64L(0x05d0fba2),
+		/* lg(128/127) = */ FLAC__U64L(0x02e58f74),
+		/* lg(256/255) = */ FLAC__U64L(0x01720d9c),
+		/* lg(512/511) = */ FLAC__U64L(0x00b8d875),
+		/* lg(1024/1023) = */ FLAC__U64L(0x005c60aa),
+		/* lg(2048/2047) = */ FLAC__U64L(0x002e2d72),
+		/* lg(4096/4095) = */ FLAC__U64L(0x00171600),
+		/* lg(8192/8191) = */ FLAC__U64L(0x000b8ad2),
+		/* lg(16384/16383) = */ FLAC__U64L(0x0005c55d),
+		/* lg(32768/32767) = */ FLAC__U64L(0x0002e2ac)
+	},
+	{
+		/*
+		 * 48 fraction bits
+		 */
+		/* undefined */ 0x00000000,
+		/* lg(2/1) = */ FLAC__U64L(0x1000000000000),
+		/* lg(4/3) = */ FLAC__U64L(0x6a3fe5c60429),
+		/* lg(8/7) = */ FLAC__U64L(0x315130157f7a),
+		/* lg(16/15) = */ FLAC__U64L(0x17d60496cfbb),
+		/* lg(32/31) = */ FLAC__U64L(0xbb9ca64ecac),
+		/* lg(64/63) = */ FLAC__U64L(0x5d0fba187cd),
+		/* lg(128/127) = */ FLAC__U64L(0x2e58f7441ee),
+		/* lg(256/255) = */ FLAC__U64L(0x1720d9c06a8),
+		/* lg(512/511) = */ FLAC__U64L(0xb8d8752173),
+		/* lg(1024/1023) = */ FLAC__U64L(0x5c60aa252e),
+		/* lg(2048/2047) = */ FLAC__U64L(0x2e2d71b0d8),
+		/* lg(4096/4095) = */ FLAC__U64L(0x1716001719),
+		/* lg(8192/8191) = */ FLAC__U64L(0xb8ad1de1b),
+		/* lg(16384/16383) = */ FLAC__U64L(0x5c55d640d),
+		/* lg(32768/32767) = */ FLAC__U64L(0x2e2abcf52)
+	}
+};
+#endif
+
+FLAC__uint32 FLAC__fixedpoint_log2(FLAC__uint32 x, unsigned fracbits, unsigned precision)
+{
+	const FLAC__uint32 ONE = (1u << fracbits);
+	const FLAC__uint32 *table = log2_lookup[fracbits >> 2];
+
+	FLAC__ASSERT(fracbits < 32);
+	FLAC__ASSERT((fracbits & 0x3) == 0);
+
+	if(x < ONE)
+		return 0;
+
+	if(precision > LOG2_LOOKUP_PRECISION)
+		precision = LOG2_LOOKUP_PRECISION;
+
+	/* Knuth's algorithm for computing logarithms, optimized for base-2 with lookup tables */
+	{
+		FLAC__uint32 y = 0;
+		FLAC__uint32 z = x >> 1, k = 1;
+		while (x > ONE && k < precision) {
+			if (x - z >= ONE) {
+				x -= z;
+				z = x >> k;
+				y += table[k];
+			}
+			else {
+				z >>= 1;
+				k++;
+			}
+		}
+		return y;
+	}
+}
+
+#endif /* defined FLAC__INTEGER_ONLY_LIBRARY */
--- a/sys/src/cmd/audio/libFLAC/format.c
+++ b/sys/src/cmd/audio/libFLAC/format.c
@@ -1,5 +1,6 @@
 /* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2000,2001,2002,2003,2004  Josh Coalson
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2014  Xiph.Org Foundation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -29,41 +30,27 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
 #include <stdio.h>
 #include <stdlib.h> /* for qsort() */
+#include <string.h> /* for memset() */
 #include "FLAC/assert.h"
 #include "FLAC/format.h"
+#include "share/compat.h"
 #include "private/format.h"
+#include "private/macros.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 char *FLAC__VENDOR_STRING = "reference libFLAC " VERSION " 20141125";
 
 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_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 */
@@ -104,6 +91,15 @@
 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_PICTURE_TYPE_LEN = 32; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN = 32; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN = 32; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN = 32; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN = 32; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN = 32; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_COLORS_LEN = 32; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN = 32; /* 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 */
@@ -110,7 +106,8 @@
 
 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_RESERVED_LEN = 1; /* bits */
+FLAC_API const unsigned FLAC__FRAME_HEADER_BLOCKING_STRATEGY_LEN = 1; /* 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 */
@@ -123,12 +120,15 @@
 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_RICE2_PARAMETER_LEN = 5; /* 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 unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER = 31; /* == (1<<FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN)-1 */
 
 FLAC_API const char * const FLAC__EntropyCodingMethodTypeString[] = {
-	"PARTITIONED_RICE"
+	"PARTITIONED_RICE",
+	"PARTITIONED_RICE2"
 };
 
 FLAC_API const unsigned FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN = 4; /* bits */
@@ -168,14 +168,57 @@
 	"APPLICATION",
 	"SEEKTABLE",
 	"VORBIS_COMMENT",
-	"CUESHEET"
+	"CUESHEET",
+	"PICTURE"
 };
 
+FLAC_API const char * const FLAC__StreamMetadata_Picture_TypeString[] = {
+	"Other",
+	"32x32 pixels 'file icon' (PNG only)",
+	"Other file icon",
+	"Cover (front)",
+	"Cover (back)",
+	"Leaflet page",
+	"Media (e.g. label side of CD)",
+	"Lead artist/lead performer/soloist",
+	"Artist/performer",
+	"Conductor",
+	"Band/Orchestra",
+	"Composer",
+	"Lyricist/text writer",
+	"Recording Location",
+	"During recording",
+	"During performance",
+	"Movie/video screen capture",
+	"A bright coloured fish",
+	"Illustration",
+	"Band/artist logotype",
+	"Publisher/Studio logotype"
+};
+
 FLAC_API FLAC__bool FLAC__format_sample_rate_is_valid(unsigned sample_rate)
 {
+	if(sample_rate == 0 || sample_rate > FLAC__MAX_SAMPLE_RATE) {
+		return false;
+	}
+	else
+		return true;
+}
+
+FLAC_API FLAC__bool FLAC__format_blocksize_is_subset(unsigned blocksize, unsigned sample_rate)
+{
+	if(blocksize > 16384)
+		return false;
+	else if(sample_rate <= 48000 && blocksize > 4608)
+		return false;
+	else
+		return true;
+}
+
+FLAC_API FLAC__bool FLAC__format_sample_rate_is_subset(unsigned sample_rate)
+{
 	if(
-		sample_rate == 0 ||
-		sample_rate > FLAC__MAX_SAMPLE_RATE ||
+		!FLAC__format_sample_rate_is_valid(sample_rate) ||
 		(
 			sample_rate >= (1u << 16) &&
 			!(sample_rate % 1000 == 0 || sample_rate % 10 == 0)
@@ -187,6 +230,7 @@
 		return true;
 }
 
+/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */
 FLAC_API FLAC__bool FLAC__format_seektable_is_legal(const FLAC__StreamMetadata_SeekTable *seek_table)
 {
 	unsigned i;
@@ -222,6 +266,7 @@
 		return 1;
 }
 
+/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */
 FLAC_API unsigned FLAC__format_seektable_sort(FLAC__StreamMetadata_SeekTable *seek_table)
 {
 	unsigned i, j;
@@ -254,6 +299,112 @@
 	return j;
 }
 
+/*
+ * also disallows non-shortest-form encodings, c.f.
+ *   http://www.unicode.org/versions/corrigendum1.html
+ * and a more clear explanation at the end of this section:
+ *   http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+ */
+static unsigned utf8len_(const FLAC__byte *utf8)
+{
+	FLAC__ASSERT(0 != utf8);
+	if ((utf8[0] & 0x80) == 0) {
+		return 1;
+	}
+	else if ((utf8[0] & 0xE0) == 0xC0 && (utf8[1] & 0xC0) == 0x80) {
+		if ((utf8[0] & 0xFE) == 0xC0) /* overlong sequence check */
+			return 0;
+		return 2;
+	}
+	else if ((utf8[0] & 0xF0) == 0xE0 && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80) {
+		if (utf8[0] == 0xE0 && (utf8[1] & 0xE0) == 0x80) /* overlong sequence check */
+			return 0;
+		/* illegal surrogates check (U+D800...U+DFFF and U+FFFE...U+FFFF) */
+		if (utf8[0] == 0xED && (utf8[1] & 0xE0) == 0xA0) /* D800-DFFF */
+			return 0;
+		if (utf8[0] == 0xEF && utf8[1] == 0xBF && (utf8[2] & 0xFE) == 0xBE) /* FFFE-FFFF */
+			return 0;
+		return 3;
+	}
+	else if ((utf8[0] & 0xF8) == 0xF0 && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80 && (utf8[3] & 0xC0) == 0x80) {
+		if (utf8[0] == 0xF0 && (utf8[1] & 0xF0) == 0x80) /* overlong sequence check */
+			return 0;
+		return 4;
+	}
+	else if ((utf8[0] & 0xFC) == 0xF8 && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80 && (utf8[3] & 0xC0) == 0x80 && (utf8[4] & 0xC0) == 0x80) {
+		if (utf8[0] == 0xF8 && (utf8[1] & 0xF8) == 0x80) /* overlong sequence check */
+			return 0;
+		return 5;
+	}
+	else if ((utf8[0] & 0xFE) == 0xFC && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80 && (utf8[3] & 0xC0) == 0x80 && (utf8[4] & 0xC0) == 0x80 && (utf8[5] & 0xC0) == 0x80) {
+		if (utf8[0] == 0xFC && (utf8[1] & 0xFC) == 0x80) /* overlong sequence check */
+			return 0;
+		return 6;
+	}
+	else {
+		return 0;
+	}
+}
+
+FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_name_is_legal(const char *name)
+{
+	char c;
+	for(c = *name; c; c = *(++name))
+		if(c < 0x20 || c == 0x3d || c > 0x7d)
+			return false;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_value_is_legal(const FLAC__byte *value, unsigned length)
+{
+	if(length == (unsigned)(-1)) {
+		while(*value) {
+			unsigned n = utf8len_(value);
+			if(n == 0)
+				return false;
+			value += n;
+		}
+	}
+	else {
+		const FLAC__byte *end = value + length;
+		while(value < end) {
+			unsigned n = utf8len_(value);
+			if(n == 0)
+				return false;
+			value += n;
+		}
+		if(value != end)
+			return false;
+	}
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_is_legal(const FLAC__byte *entry, unsigned length)
+{
+	const FLAC__byte *s, *end;
+
+	for(s = entry, end = s + length; s < end && *s != '='; s++) {
+		if(*s < 0x20 || *s > 0x7D)
+			return false;
+	}
+	if(s == end)
+		return false;
+
+	s++; /* skip '=' */
+
+	while(s < end) {
+		unsigned n = utf8len_(s);
+		if(n == 0)
+			return false;
+		s += n;
+	}
+	if(s != end)
+		return false;
+
+	return true;
+}
+
+/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */
 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;
@@ -293,7 +444,12 @@
 		}
 
 		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";
+			if(violation) {
+				if(i == cue_sheet->num_tracks-1) /* the lead-out track... */
+					*violation = "CD-DA cue sheet lead-out offset must be evenly divisible by 588 samples";
+				else
+					*violation = "CD-DA cue sheet track offset must be evenly divisible by 588 samples";
+			}
 			return false;
 		}
 
@@ -327,6 +483,31 @@
 	return true;
 }
 
+/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */
+FLAC_API FLAC__bool FLAC__format_picture_is_legal(const FLAC__StreamMetadata_Picture *picture, const char **violation)
+{
+	char *p;
+	FLAC__byte *b;
+
+	for(p = picture->mime_type; *p; p++) {
+		if(*p < 0x20 || *p > 0x7e) {
+			if(violation) *violation = "MIME type string must contain only printable ASCII characters (0x20-0x7e)";
+			return false;
+		}
+	}
+
+	for(b = picture->description; *b; ) {
+		unsigned n = utf8len_(b);
+		if(n == 0) {
+			if(violation) *violation = "description string must be valid UTF-8";
+			return false;
+		}
+		b += n;
+	}
+
+	return true;
+}
+
 /*
  * These routines are private to libFLAC
  */
@@ -347,7 +528,7 @@
 		max_rice_partition_order++;
 		blocksize >>= 1;
 	}
-	return min(FLAC__MAX_RICE_PARTITION_ORDER, max_rice_partition_order);
+	return flac_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)
@@ -392,10 +573,11 @@
 	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))))
+		if(0 == (object->parameters = 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))))
+		if(0 == (object->raw_bits = realloc(object->raw_bits, sizeof(unsigned)*(1 << max_partition_order))))
 			return false;
+		memset(object->raw_bits, 0, sizeof(unsigned)*(1 << max_partition_order));
 		object->capacity_by_order = max_partition_order;
 	}
 
--- a/sys/src/cmd/audio/libFLAC/lpc.c
+++ b/sys/src/cmd/audio/libFLAC/lpc.c
@@ -1,5 +1,6 @@
 /* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2000,2001,2002,2003,2004  Josh Coalson
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2014  Xiph.Org Foundation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -29,20 +30,49 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
 #include <math.h>
+
 #include "FLAC/assert.h"
 #include "FLAC/format.h"
+#include "share/compat.h"
 #include "private/bitmath.h"
 #include "private/lpc.h"
+#include "private/macros.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
+/* OPT: #undef'ing this may improve the speed on some architectures */
+#define FLAC__LPC_UNROLLED_FILTER_LOOPS
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+
+#if !defined(HAVE_LROUND)
+#if defined(_MSC_VER)
+#include <float.h>
+#define copysign _copysign
+#elif defined(__GNUC__)
+#define copysign __builtin_copysign
+#elif defined(Plan9)
+#define copysign(x,y) ((x > 0.0 && y < 0.0) || (x < 0.0 && y > 0.0)) ? -x : x
 #endif
+static inline long int lround(double x) {
+    return (long)(x + copysign (0.5, x));
+}
+/* If this fails, we are in the presence of a mid 90's compiler, move along... */
+#endif
 
+void FLAC__lpc_window_data(const FLAC__int32 in[], const FLAC__real window[], FLAC__real out[], unsigned data_len)
+{
+	unsigned i;
+	for(i = 0; i < data_len; i++)
+		out[i] = in[i] * window[i];
+}
+
 void FLAC__lpc_compute_autocorrelation(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[])
 {
 	/* a readable, but slower, version */
@@ -53,6 +83,13 @@
 	FLAC__ASSERT(lag > 0);
 	FLAC__ASSERT(lag <= data_len);
 
+	/*
+	 * Technically we should subtract the mean first like so:
+	 *   for(i = 0; i < data_len; i++)
+	 *     data[i] -= mean;
+	 * but it appears not to make enough of a difference to matter, and
+	 * most signals are already closely centered around zero
+	 */
 	while(lag--) {
 		for(i = lag, d = 0.0; i < data_len; i++)
 			d += data[i] * data[i - lag];
@@ -85,28 +122,29 @@
 	}
 }
 
-void FLAC__lpc_compute_lp_coefficients(const FLAC__real autoc[], unsigned max_order, FLAC__real lp_coeff[][FLAC__MAX_LPC_ORDER], FLAC__real error[])
+void FLAC__lpc_compute_lp_coefficients(const FLAC__real autoc[], unsigned *max_order, FLAC__real lp_coeff[][FLAC__MAX_LPC_ORDER], FLAC__double error[])
 {
 	unsigned i, j;
-	double r, err, ref[FLAC__MAX_LPC_ORDER], lpc[FLAC__MAX_LPC_ORDER];
+	FLAC__double r, err, lpc[FLAC__MAX_LPC_ORDER];
 
-	FLAC__ASSERT(0 < max_order);
-	FLAC__ASSERT(max_order <= FLAC__MAX_LPC_ORDER);
+	FLAC__ASSERT(0 != max_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++) {
+	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);
+		r /= err;
 
 		/* Update LPC coefficients and total error. */
 		lpc[i]=r;
 		for(j = 0; j < (i>>1); j++) {
-			double tmp = lpc[j];
+			FLAC__double tmp = lpc[j];
 			lpc[j] += r * lpc[i-1-j];
 			lpc[i-1-j] += r * tmp;
 		}
@@ -118,7 +156,13 @@
 		/* 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;
+		error[i] = err;
+
+		/* see SF bug https://sourceforge.net/p/flac/bugs/234/ */
+		if(err == 0.0) {
+			*max_order = i+1;
+			return;
+		}
 	}
 }
 
@@ -125,10 +169,8 @@
 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__double cmax;
 	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);
@@ -139,19 +181,21 @@
 	qmin = -qmax;
 	qmax--;
 
+	/* calc cmax = max( |lp_coeff[i]| ) */
+	cmax = 0.0;
 	for(i = 0; i < order; i++) {
-		if(lp_coeff[i] == 0.0)
-			continue;
-		d = fabs(lp_coeff[i]);
+		const FLAC__double 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 {
+		const int max_shiftlimit = (1 << (FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN-1)) - 1;
+		const int min_shiftlimit = -max_shiftlimit - 1;
 		int log2cmax;
 
 		(void)frexp(cmax, &log2cmax);
@@ -158,58 +202,75 @@
 		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 > max_shiftlimit)
+			*shift = max_shiftlimit;
+		else if(*shift < min_shiftlimit)
+			return 1;
 	}
 
 	if(*shift >= 0) {
+		FLAC__double error = 0.0;
+		FLAC__int32 q;
 		for(i = 0; i < order; i++) {
-			qlp_coeff[i] = (FLAC__int32)floor((double)lp_coeff[i] * (double)(1 << *shift));
+			error += lp_coeff[i] * (1 << *shift);
+			q = lround(error);
 
-			/* 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)));
+			if(q > qmax+1) /* we expect q==qmax+1 occasionally due to rounding */
+				fprintf(stderr,"FLAC__lpc_quantize_coefficients: quantizer overflow: q>qmax %d>%d shift=%d cmax=%f precision=%u lpc[%u]=%f\n",q,qmax,*shift,cmax,precision+1,i,lp_coeff[i]);
+			else if(q < qmin)
+				fprintf(stderr,"FLAC__lpc_quantize_coefficients: quantizer overflow: q<qmin %d<%d shift=%d cmax=%f precision=%u lpc[%u]=%f\n",q,qmin,*shift,cmax,precision+1,i,lp_coeff[i]);
 #endif
-				cmax *= 2.0;
-				goto redo_it;
-			}
+			if(q > qmax)
+				q = qmax;
+			else if(q < qmin)
+				q = qmin;
+			error -= q;
+			qlp_coeff[i] = q;
 		}
 	}
-	else { /* (*shift < 0) */
+	/* negative shift is very rare but due to design flaw, negative shift is
+	 * a NOP in the decoder, so it must be handled specially by scaling down
+	 * coeffs
+	 */
+	else {
 		const int nshift = -(*shift);
+		FLAC__double error = 0.0;
+		FLAC__int32 q;
 #ifdef DEBUG
-		fprintf(stderr,"FLAC__lpc_quantize_coefficients: negative shift = %d\n", *shift);
+		fprintf(stderr,"FLAC__lpc_quantize_coefficients: negative shift=%d order=%u cmax=%f\n", *shift, order, cmax);
 #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) {
+			error += lp_coeff[i] / (1 << nshift);
+			q = lround(error);
 #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)));
+			if(q > qmax+1) /* we expect q==qmax+1 occasionally due to rounding */
+				fprintf(stderr,"FLAC__lpc_quantize_coefficients: quantizer overflow: q>qmax %d>%d shift=%d cmax=%f precision=%u lpc[%u]=%f\n",q,qmax,*shift,cmax,precision+1,i,lp_coeff[i]);
+			else if(q < qmin)
+				fprintf(stderr,"FLAC__lpc_quantize_coefficients: quantizer overflow: q<qmin %d<%d shift=%d cmax=%f precision=%u lpc[%u]=%f\n",q,qmin,*shift,cmax,precision+1,i,lp_coeff[i]);
 #endif
-				cmax *= 2.0;
-				goto redo_it;
-			}
+			if(q > qmax)
+				q = qmax;
+			else if(q < qmin)
+				q = qmin;
+			error -= q;
+			qlp_coeff[i] = q;
 		}
+		*shift = 0;
 	}
 
 	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[])
+#if defined(_MSC_VER)
+// silence MSVC warnings about __restrict modifier
+#pragma warning ( disable : 4028 )
+#endif
+
+void FLAC__lpc_compute_residual_from_qlp_coefficients(const FLAC__int32 * flac_restrict data, unsigned data_len, const FLAC__int32 * flac_restrict qlp_coeff, unsigned order, int lp_quantization, FLAC__int32 * flac_restrict residual)
+#if defined(FLAC__OVERFLOW_DETECT) || !defined(FLAC__LPC_UNROLLED_FILTER_LOOPS)
 {
-#ifdef FLAC__OVERFLOW_DETECT
 	FLAC__int64 sumo;
-#endif
 	unsigned i, j;
 	FLAC__int32 sum;
 	const FLAC__int32 *history;
@@ -223,23 +284,13 @@
 	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
+				fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients: OVERFLOW, i=%u, j=%u, c=%d, d=%d, sumo=%" PRId64 "\n",i,j,qlp_coeff[j],*history,sumo);
 		}
 		*(residual++) = *(data++) - (sum >> lp_quantization);
 	}
@@ -253,8 +304,231 @@
 	}
 	*/
 }
+#else /* fully unrolled version for normal use */
+{
+	int i;
+	FLAC__int32 sum;
 
-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[])
+	FLAC__ASSERT(order > 0);
+	FLAC__ASSERT(order <= 32);
+
+	/*
+	 * We do unique versions up to 12th order since that's the subset limit.
+	 * Also they are roughly ordered to match frequency of occurrence to
+	 * minimize branching.
+	 */
+	if(order <= 12) {
+		if(order > 8) {
+			if(order > 10) {
+				if(order == 12) {
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[11] * data[i-12];
+						sum += qlp_coeff[10] * data[i-11];
+						sum += qlp_coeff[9] * data[i-10];
+						sum += qlp_coeff[8] * data[i-9];
+						sum += qlp_coeff[7] * data[i-8];
+						sum += qlp_coeff[6] * data[i-7];
+						sum += qlp_coeff[5] * data[i-6];
+						sum += qlp_coeff[4] * data[i-5];
+						sum += qlp_coeff[3] * data[i-4];
+						sum += qlp_coeff[2] * data[i-3];
+						sum += qlp_coeff[1] * data[i-2];
+						sum += qlp_coeff[0] * data[i-1];
+						residual[i] = data[i] - (sum >> lp_quantization);
+					}
+				}
+				else { /* order == 11 */
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[10] * data[i-11];
+						sum += qlp_coeff[9] * data[i-10];
+						sum += qlp_coeff[8] * data[i-9];
+						sum += qlp_coeff[7] * data[i-8];
+						sum += qlp_coeff[6] * data[i-7];
+						sum += qlp_coeff[5] * data[i-6];
+						sum += qlp_coeff[4] * data[i-5];
+						sum += qlp_coeff[3] * data[i-4];
+						sum += qlp_coeff[2] * data[i-3];
+						sum += qlp_coeff[1] * data[i-2];
+						sum += qlp_coeff[0] * data[i-1];
+						residual[i] = data[i] - (sum >> lp_quantization);
+					}
+				}
+			}
+			else {
+				if(order == 10) {
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[9] * data[i-10];
+						sum += qlp_coeff[8] * data[i-9];
+						sum += qlp_coeff[7] * data[i-8];
+						sum += qlp_coeff[6] * data[i-7];
+						sum += qlp_coeff[5] * data[i-6];
+						sum += qlp_coeff[4] * data[i-5];
+						sum += qlp_coeff[3] * data[i-4];
+						sum += qlp_coeff[2] * data[i-3];
+						sum += qlp_coeff[1] * data[i-2];
+						sum += qlp_coeff[0] * data[i-1];
+						residual[i] = data[i] - (sum >> lp_quantization);
+					}
+				}
+				else { /* order == 9 */
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[8] * data[i-9];
+						sum += qlp_coeff[7] * data[i-8];
+						sum += qlp_coeff[6] * data[i-7];
+						sum += qlp_coeff[5] * data[i-6];
+						sum += qlp_coeff[4] * data[i-5];
+						sum += qlp_coeff[3] * data[i-4];
+						sum += qlp_coeff[2] * data[i-3];
+						sum += qlp_coeff[1] * data[i-2];
+						sum += qlp_coeff[0] * data[i-1];
+						residual[i] = data[i] - (sum >> lp_quantization);
+					}
+				}
+			}
+		}
+		else if(order > 4) {
+			if(order > 6) {
+				if(order == 8) {
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[7] * data[i-8];
+						sum += qlp_coeff[6] * data[i-7];
+						sum += qlp_coeff[5] * data[i-6];
+						sum += qlp_coeff[4] * data[i-5];
+						sum += qlp_coeff[3] * data[i-4];
+						sum += qlp_coeff[2] * data[i-3];
+						sum += qlp_coeff[1] * data[i-2];
+						sum += qlp_coeff[0] * data[i-1];
+						residual[i] = data[i] - (sum >> lp_quantization);
+					}
+				}
+				else { /* order == 7 */
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[6] * data[i-7];
+						sum += qlp_coeff[5] * data[i-6];
+						sum += qlp_coeff[4] * data[i-5];
+						sum += qlp_coeff[3] * data[i-4];
+						sum += qlp_coeff[2] * data[i-3];
+						sum += qlp_coeff[1] * data[i-2];
+						sum += qlp_coeff[0] * data[i-1];
+						residual[i] = data[i] - (sum >> lp_quantization);
+					}
+				}
+			}
+			else {
+				if(order == 6) {
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[5] * data[i-6];
+						sum += qlp_coeff[4] * data[i-5];
+						sum += qlp_coeff[3] * data[i-4];
+						sum += qlp_coeff[2] * data[i-3];
+						sum += qlp_coeff[1] * data[i-2];
+						sum += qlp_coeff[0] * data[i-1];
+						residual[i] = data[i] - (sum >> lp_quantization);
+					}
+				}
+				else { /* order == 5 */
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[4] * data[i-5];
+						sum += qlp_coeff[3] * data[i-4];
+						sum += qlp_coeff[2] * data[i-3];
+						sum += qlp_coeff[1] * data[i-2];
+						sum += qlp_coeff[0] * data[i-1];
+						residual[i] = data[i] - (sum >> lp_quantization);
+					}
+				}
+			}
+		}
+		else {
+			if(order > 2) {
+				if(order == 4) {
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[3] * data[i-4];
+						sum += qlp_coeff[2] * data[i-3];
+						sum += qlp_coeff[1] * data[i-2];
+						sum += qlp_coeff[0] * data[i-1];
+						residual[i] = data[i] - (sum >> lp_quantization);
+					}
+				}
+				else { /* order == 3 */
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[2] * data[i-3];
+						sum += qlp_coeff[1] * data[i-2];
+						sum += qlp_coeff[0] * data[i-1];
+						residual[i] = data[i] - (sum >> lp_quantization);
+					}
+				}
+			}
+			else {
+				if(order == 2) {
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[1] * data[i-2];
+						sum += qlp_coeff[0] * data[i-1];
+						residual[i] = data[i] - (sum >> lp_quantization);
+					}
+				}
+				else { /* order == 1 */
+					for(i = 0; i < (int)data_len; i++)
+						residual[i] = data[i] - ((qlp_coeff[0] * data[i-1]) >> lp_quantization);
+				}
+			}
+		}
+	}
+	else { /* order > 12 */
+		for(i = 0; i < (int)data_len; i++) {
+			sum = 0;
+			switch(order) {
+				case 32: sum += qlp_coeff[31] * data[i-32];
+				case 31: sum += qlp_coeff[30] * data[i-31];
+				case 30: sum += qlp_coeff[29] * data[i-30];
+				case 29: sum += qlp_coeff[28] * data[i-29];
+				case 28: sum += qlp_coeff[27] * data[i-28];
+				case 27: sum += qlp_coeff[26] * data[i-27];
+				case 26: sum += qlp_coeff[25] * data[i-26];
+				case 25: sum += qlp_coeff[24] * data[i-25];
+				case 24: sum += qlp_coeff[23] * data[i-24];
+				case 23: sum += qlp_coeff[22] * data[i-23];
+				case 22: sum += qlp_coeff[21] * data[i-22];
+				case 21: sum += qlp_coeff[20] * data[i-21];
+				case 20: sum += qlp_coeff[19] * data[i-20];
+				case 19: sum += qlp_coeff[18] * data[i-19];
+				case 18: sum += qlp_coeff[17] * data[i-18];
+				case 17: sum += qlp_coeff[16] * data[i-17];
+				case 16: sum += qlp_coeff[15] * data[i-16];
+				case 15: sum += qlp_coeff[14] * data[i-15];
+				case 14: sum += qlp_coeff[13] * data[i-14];
+				case 13: sum += qlp_coeff[12] * data[i-13];
+				         sum += qlp_coeff[11] * data[i-12];
+				         sum += qlp_coeff[10] * data[i-11];
+				         sum += qlp_coeff[ 9] * data[i-10];
+				         sum += qlp_coeff[ 8] * data[i- 9];
+				         sum += qlp_coeff[ 7] * data[i- 8];
+				         sum += qlp_coeff[ 6] * data[i- 7];
+				         sum += qlp_coeff[ 5] * data[i- 6];
+				         sum += qlp_coeff[ 4] * data[i- 5];
+				         sum += qlp_coeff[ 3] * data[i- 4];
+				         sum += qlp_coeff[ 2] * data[i- 3];
+				         sum += qlp_coeff[ 1] * data[i- 2];
+				         sum += qlp_coeff[ 0] * data[i- 1];
+			}
+			residual[i] = data[i] - (sum >> lp_quantization);
+		}
+	}
+}
+#endif
+
+void FLAC__lpc_compute_residual_from_qlp_coefficients_wide(const FLAC__int32 * flac_restrict data, unsigned data_len, const FLAC__int32 * flac_restrict qlp_coeff, unsigned order, int lp_quantization, FLAC__int32 * flac_restrict residual)
+#if defined(FLAC__OVERFLOW_DETECT) || !defined(FLAC__LPC_UNROLLED_FILTER_LOOPS)
 {
 	unsigned i, j;
 	FLAC__int64 sum;
@@ -273,28 +547,249 @@
 		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);
+			fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients_wide: OVERFLOW, i=%u, sum=%" PRId64 "\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));
+			fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients_wide: OVERFLOW, i=%u, data=%d, sum=%" PRId64 ", residual=%" PRId64 "\n", i, *data, (int64_t)(sum >> lp_quantization), ((FLAC__int64)(*data) - (sum >> lp_quantization)));
 			break;
 		}
-#endif
 		*(residual++) = *(data++) - (FLAC__int32)(sum >> lp_quantization);
 	}
 }
+#else /* fully unrolled version for normal use */
+{
+	int i;
+	FLAC__int64 sum;
 
-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[])
+	FLAC__ASSERT(order > 0);
+	FLAC__ASSERT(order <= 32);
+
+	/*
+	 * We do unique versions up to 12th order since that's the subset limit.
+	 * Also they are roughly ordered to match frequency of occurrence to
+	 * minimize branching.
+	 */
+	if(order <= 12) {
+		if(order > 8) {
+			if(order > 10) {
+				if(order == 12) {
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[11] * (FLAC__int64)data[i-12];
+						sum += qlp_coeff[10] * (FLAC__int64)data[i-11];
+						sum += qlp_coeff[9] * (FLAC__int64)data[i-10];
+						sum += qlp_coeff[8] * (FLAC__int64)data[i-9];
+						sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+						sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+						sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+						sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+						sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+						sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+						sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+						sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+						residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+					}
+				}
+				else { /* order == 11 */
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[10] * (FLAC__int64)data[i-11];
+						sum += qlp_coeff[9] * (FLAC__int64)data[i-10];
+						sum += qlp_coeff[8] * (FLAC__int64)data[i-9];
+						sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+						sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+						sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+						sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+						sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+						sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+						sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+						sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+						residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+					}
+				}
+			}
+			else {
+				if(order == 10) {
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[9] * (FLAC__int64)data[i-10];
+						sum += qlp_coeff[8] * (FLAC__int64)data[i-9];
+						sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+						sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+						sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+						sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+						sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+						sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+						sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+						sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+						residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+					}
+				}
+				else { /* order == 9 */
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[8] * (FLAC__int64)data[i-9];
+						sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+						sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+						sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+						sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+						sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+						sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+						sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+						sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+						residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+					}
+				}
+			}
+		}
+		else if(order > 4) {
+			if(order > 6) {
+				if(order == 8) {
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+						sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+						sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+						sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+						sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+						sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+						sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+						sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+						residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+					}
+				}
+				else { /* order == 7 */
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+						sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+						sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+						sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+						sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+						sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+						sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+						residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+					}
+				}
+			}
+			else {
+				if(order == 6) {
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+						sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+						sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+						sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+						sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+						sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+						residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+					}
+				}
+				else { /* order == 5 */
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+						sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+						sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+						sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+						sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+						residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+					}
+				}
+			}
+		}
+		else {
+			if(order > 2) {
+				if(order == 4) {
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+						sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+						sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+						sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+						residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+					}
+				}
+				else { /* order == 3 */
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+						sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+						sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+						residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+					}
+				}
+			}
+			else {
+				if(order == 2) {
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+						sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+						residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+					}
+				}
+				else { /* order == 1 */
+					for(i = 0; i < (int)data_len; i++)
+						residual[i] = data[i] - (FLAC__int32)((qlp_coeff[0] * (FLAC__int64)data[i-1]) >> lp_quantization);
+				}
+			}
+		}
+	}
+	else { /* order > 12 */
+		for(i = 0; i < (int)data_len; i++) {
+			sum = 0;
+			switch(order) {
+				case 32: sum += qlp_coeff[31] * (FLAC__int64)data[i-32];
+				case 31: sum += qlp_coeff[30] * (FLAC__int64)data[i-31];
+				case 30: sum += qlp_coeff[29] * (FLAC__int64)data[i-30];
+				case 29: sum += qlp_coeff[28] * (FLAC__int64)data[i-29];
+				case 28: sum += qlp_coeff[27] * (FLAC__int64)data[i-28];
+				case 27: sum += qlp_coeff[26] * (FLAC__int64)data[i-27];
+				case 26: sum += qlp_coeff[25] * (FLAC__int64)data[i-26];
+				case 25: sum += qlp_coeff[24] * (FLAC__int64)data[i-25];
+				case 24: sum += qlp_coeff[23] * (FLAC__int64)data[i-24];
+				case 23: sum += qlp_coeff[22] * (FLAC__int64)data[i-23];
+				case 22: sum += qlp_coeff[21] * (FLAC__int64)data[i-22];
+				case 21: sum += qlp_coeff[20] * (FLAC__int64)data[i-21];
+				case 20: sum += qlp_coeff[19] * (FLAC__int64)data[i-20];
+				case 19: sum += qlp_coeff[18] * (FLAC__int64)data[i-19];
+				case 18: sum += qlp_coeff[17] * (FLAC__int64)data[i-18];
+				case 17: sum += qlp_coeff[16] * (FLAC__int64)data[i-17];
+				case 16: sum += qlp_coeff[15] * (FLAC__int64)data[i-16];
+				case 15: sum += qlp_coeff[14] * (FLAC__int64)data[i-15];
+				case 14: sum += qlp_coeff[13] * (FLAC__int64)data[i-14];
+				case 13: sum += qlp_coeff[12] * (FLAC__int64)data[i-13];
+				         sum += qlp_coeff[11] * (FLAC__int64)data[i-12];
+				         sum += qlp_coeff[10] * (FLAC__int64)data[i-11];
+				         sum += qlp_coeff[ 9] * (FLAC__int64)data[i-10];
+				         sum += qlp_coeff[ 8] * (FLAC__int64)data[i- 9];
+				         sum += qlp_coeff[ 7] * (FLAC__int64)data[i- 8];
+				         sum += qlp_coeff[ 6] * (FLAC__int64)data[i- 7];
+				         sum += qlp_coeff[ 5] * (FLAC__int64)data[i- 6];
+				         sum += qlp_coeff[ 4] * (FLAC__int64)data[i- 5];
+				         sum += qlp_coeff[ 3] * (FLAC__int64)data[i- 4];
+				         sum += qlp_coeff[ 2] * (FLAC__int64)data[i- 3];
+				         sum += qlp_coeff[ 1] * (FLAC__int64)data[i- 2];
+				         sum += qlp_coeff[ 0] * (FLAC__int64)data[i- 1];
+			}
+			residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+		}
+	}
+}
+#endif
+
+#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */
+
+void FLAC__lpc_restore_signal(const FLAC__int32 * flac_restrict residual, unsigned data_len, const FLAC__int32 * flac_restrict qlp_coeff, unsigned order, int lp_quantization, FLAC__int32 * flac_restrict data)
+#if defined(FLAC__OVERFLOW_DETECT) || !defined(FLAC__LPC_UNROLLED_FILTER_LOOPS)
 {
-#ifdef FLAC__OVERFLOW_DETECT
 	FLAC__int64 sumo;
-#endif
 	unsigned i, j;
 	FLAC__int32 sum;
-	const FLAC__int32 *history;
+	const FLAC__int32 *r = residual, *history;
 
 #ifdef FLAC__OVERFLOW_DETECT_VERBOSE
 	fprintf(stderr,"FLAC__lpc_restore_signal: data_len=%d, order=%u, lpq=%d",data_len,order,lp_quantization);
@@ -305,25 +800,16 @@
 	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
+				fprintf(stderr,"FLAC__lpc_restore_signal: OVERFLOW, i=%u, j=%u, c=%d, d=%d, sumo=%" PRId64 "\n",i,j,qlp_coeff[j],*history,sumo);
 		}
-		*(data++) = *(residual++) + (sum >> lp_quantization);
+		*(data++) = *(r++) + (sum >> lp_quantization);
 	}
 
 	/* Here's a slower but clearer version:
@@ -335,12 +821,235 @@
 	}
 	*/
 }
+#else /* fully unrolled version for normal use */
+{
+	int i;
+	FLAC__int32 sum;
 
-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[])
+	FLAC__ASSERT(order > 0);
+	FLAC__ASSERT(order <= 32);
+
+	/*
+	 * We do unique versions up to 12th order since that's the subset limit.
+	 * Also they are roughly ordered to match frequency of occurrence to
+	 * minimize branching.
+	 */
+	if(order <= 12) {
+		if(order > 8) {
+			if(order > 10) {
+				if(order == 12) {
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[11] * data[i-12];
+						sum += qlp_coeff[10] * data[i-11];
+						sum += qlp_coeff[9] * data[i-10];
+						sum += qlp_coeff[8] * data[i-9];
+						sum += qlp_coeff[7] * data[i-8];
+						sum += qlp_coeff[6] * data[i-7];
+						sum += qlp_coeff[5] * data[i-6];
+						sum += qlp_coeff[4] * data[i-5];
+						sum += qlp_coeff[3] * data[i-4];
+						sum += qlp_coeff[2] * data[i-3];
+						sum += qlp_coeff[1] * data[i-2];
+						sum += qlp_coeff[0] * data[i-1];
+						data[i] = residual[i] + (sum >> lp_quantization);
+					}
+				}
+				else { /* order == 11 */
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[10] * data[i-11];
+						sum += qlp_coeff[9] * data[i-10];
+						sum += qlp_coeff[8] * data[i-9];
+						sum += qlp_coeff[7] * data[i-8];
+						sum += qlp_coeff[6] * data[i-7];
+						sum += qlp_coeff[5] * data[i-6];
+						sum += qlp_coeff[4] * data[i-5];
+						sum += qlp_coeff[3] * data[i-4];
+						sum += qlp_coeff[2] * data[i-3];
+						sum += qlp_coeff[1] * data[i-2];
+						sum += qlp_coeff[0] * data[i-1];
+						data[i] = residual[i] + (sum >> lp_quantization);
+					}
+				}
+			}
+			else {
+				if(order == 10) {
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[9] * data[i-10];
+						sum += qlp_coeff[8] * data[i-9];
+						sum += qlp_coeff[7] * data[i-8];
+						sum += qlp_coeff[6] * data[i-7];
+						sum += qlp_coeff[5] * data[i-6];
+						sum += qlp_coeff[4] * data[i-5];
+						sum += qlp_coeff[3] * data[i-4];
+						sum += qlp_coeff[2] * data[i-3];
+						sum += qlp_coeff[1] * data[i-2];
+						sum += qlp_coeff[0] * data[i-1];
+						data[i] = residual[i] + (sum >> lp_quantization);
+					}
+				}
+				else { /* order == 9 */
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[8] * data[i-9];
+						sum += qlp_coeff[7] * data[i-8];
+						sum += qlp_coeff[6] * data[i-7];
+						sum += qlp_coeff[5] * data[i-6];
+						sum += qlp_coeff[4] * data[i-5];
+						sum += qlp_coeff[3] * data[i-4];
+						sum += qlp_coeff[2] * data[i-3];
+						sum += qlp_coeff[1] * data[i-2];
+						sum += qlp_coeff[0] * data[i-1];
+						data[i] = residual[i] + (sum >> lp_quantization);
+					}
+				}
+			}
+		}
+		else if(order > 4) {
+			if(order > 6) {
+				if(order == 8) {
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[7] * data[i-8];
+						sum += qlp_coeff[6] * data[i-7];
+						sum += qlp_coeff[5] * data[i-6];
+						sum += qlp_coeff[4] * data[i-5];
+						sum += qlp_coeff[3] * data[i-4];
+						sum += qlp_coeff[2] * data[i-3];
+						sum += qlp_coeff[1] * data[i-2];
+						sum += qlp_coeff[0] * data[i-1];
+						data[i] = residual[i] + (sum >> lp_quantization);
+					}
+				}
+				else { /* order == 7 */
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[6] * data[i-7];
+						sum += qlp_coeff[5] * data[i-6];
+						sum += qlp_coeff[4] * data[i-5];
+						sum += qlp_coeff[3] * data[i-4];
+						sum += qlp_coeff[2] * data[i-3];
+						sum += qlp_coeff[1] * data[i-2];
+						sum += qlp_coeff[0] * data[i-1];
+						data[i] = residual[i] + (sum >> lp_quantization);
+					}
+				}
+			}
+			else {
+				if(order == 6) {
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[5] * data[i-6];
+						sum += qlp_coeff[4] * data[i-5];
+						sum += qlp_coeff[3] * data[i-4];
+						sum += qlp_coeff[2] * data[i-3];
+						sum += qlp_coeff[1] * data[i-2];
+						sum += qlp_coeff[0] * data[i-1];
+						data[i] = residual[i] + (sum >> lp_quantization);
+					}
+				}
+				else { /* order == 5 */
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[4] * data[i-5];
+						sum += qlp_coeff[3] * data[i-4];
+						sum += qlp_coeff[2] * data[i-3];
+						sum += qlp_coeff[1] * data[i-2];
+						sum += qlp_coeff[0] * data[i-1];
+						data[i] = residual[i] + (sum >> lp_quantization);
+					}
+				}
+			}
+		}
+		else {
+			if(order > 2) {
+				if(order == 4) {
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[3] * data[i-4];
+						sum += qlp_coeff[2] * data[i-3];
+						sum += qlp_coeff[1] * data[i-2];
+						sum += qlp_coeff[0] * data[i-1];
+						data[i] = residual[i] + (sum >> lp_quantization);
+					}
+				}
+				else { /* order == 3 */
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[2] * data[i-3];
+						sum += qlp_coeff[1] * data[i-2];
+						sum += qlp_coeff[0] * data[i-1];
+						data[i] = residual[i] + (sum >> lp_quantization);
+					}
+				}
+			}
+			else {
+				if(order == 2) {
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[1] * data[i-2];
+						sum += qlp_coeff[0] * data[i-1];
+						data[i] = residual[i] + (sum >> lp_quantization);
+					}
+				}
+				else { /* order == 1 */
+					for(i = 0; i < (int)data_len; i++)
+						data[i] = residual[i] + ((qlp_coeff[0] * data[i-1]) >> lp_quantization);
+				}
+			}
+		}
+	}
+	else { /* order > 12 */
+		for(i = 0; i < (int)data_len; i++) {
+			sum = 0;
+			switch(order) {
+				case 32: sum += qlp_coeff[31] * data[i-32];
+				case 31: sum += qlp_coeff[30] * data[i-31];
+				case 30: sum += qlp_coeff[29] * data[i-30];
+				case 29: sum += qlp_coeff[28] * data[i-29];
+				case 28: sum += qlp_coeff[27] * data[i-28];
+				case 27: sum += qlp_coeff[26] * data[i-27];
+				case 26: sum += qlp_coeff[25] * data[i-26];
+				case 25: sum += qlp_coeff[24] * data[i-25];
+				case 24: sum += qlp_coeff[23] * data[i-24];
+				case 23: sum += qlp_coeff[22] * data[i-23];
+				case 22: sum += qlp_coeff[21] * data[i-22];
+				case 21: sum += qlp_coeff[20] * data[i-21];
+				case 20: sum += qlp_coeff[19] * data[i-20];
+				case 19: sum += qlp_coeff[18] * data[i-19];
+				case 18: sum += qlp_coeff[17] * data[i-18];
+				case 17: sum += qlp_coeff[16] * data[i-17];
+				case 16: sum += qlp_coeff[15] * data[i-16];
+				case 15: sum += qlp_coeff[14] * data[i-15];
+				case 14: sum += qlp_coeff[13] * data[i-14];
+				case 13: sum += qlp_coeff[12] * data[i-13];
+				         sum += qlp_coeff[11] * data[i-12];
+				         sum += qlp_coeff[10] * data[i-11];
+				         sum += qlp_coeff[ 9] * data[i-10];
+				         sum += qlp_coeff[ 8] * data[i- 9];
+				         sum += qlp_coeff[ 7] * data[i- 8];
+				         sum += qlp_coeff[ 6] * data[i- 7];
+				         sum += qlp_coeff[ 5] * data[i- 6];
+				         sum += qlp_coeff[ 4] * data[i- 5];
+				         sum += qlp_coeff[ 3] * data[i- 4];
+				         sum += qlp_coeff[ 2] * data[i- 3];
+				         sum += qlp_coeff[ 1] * data[i- 2];
+				         sum += qlp_coeff[ 0] * data[i- 1];
+			}
+			data[i] = residual[i] + (sum >> lp_quantization);
+		}
+	}
+}
+#endif
+
+void FLAC__lpc_restore_signal_wide(const FLAC__int32 * flac_restrict residual, unsigned data_len, const FLAC__int32 * flac_restrict qlp_coeff, unsigned order, int lp_quantization, FLAC__int32 * flac_restrict data)
+#if defined(FLAC__OVERFLOW_DETECT) || !defined(FLAC__LPC_UNROLLED_FILTER_LOOPS)
 {
 	unsigned i, j;
 	FLAC__int64 sum;
-	const FLAC__int32 *history;
+	const FLAC__int32 *r = residual, *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);
@@ -355,42 +1064,268 @@
 		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);
+			fprintf(stderr,"FLAC__lpc_restore_signal_wide: OVERFLOW, i=%u, sum=%" PRId64 "\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));
+		if(FLAC__bitmath_silog2_wide((FLAC__int64)(*r) + (sum >> lp_quantization)) > 32) {
+			fprintf(stderr,"FLAC__lpc_restore_signal_wide: OVERFLOW, i=%u, residual=%d, sum=%" PRId64 ", data=%" PRId64 "\n", i, *r, (sum >> lp_quantization), ((FLAC__int64)(*r) + (sum >> lp_quantization)));
 			break;
 		}
-#endif
-		*(data++) = *(residual++) + (FLAC__int32)(sum >> lp_quantization);
+		*(data++) = *(r++) + (FLAC__int32)(sum >> lp_quantization);
 	}
 }
+#else /* fully unrolled version for normal use */
+{
+	int i;
+	FLAC__int64 sum;
 
-FLAC__real FLAC__lpc_compute_expected_bits_per_residual_sample(FLAC__real lpc_error, unsigned total_samples)
+	FLAC__ASSERT(order > 0);
+	FLAC__ASSERT(order <= 32);
+
+	/*
+	 * We do unique versions up to 12th order since that's the subset limit.
+	 * Also they are roughly ordered to match frequency of occurrence to
+	 * minimize branching.
+	 */
+	if(order <= 12) {
+		if(order > 8) {
+			if(order > 10) {
+				if(order == 12) {
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[11] * (FLAC__int64)data[i-12];
+						sum += qlp_coeff[10] * (FLAC__int64)data[i-11];
+						sum += qlp_coeff[9] * (FLAC__int64)data[i-10];
+						sum += qlp_coeff[8] * (FLAC__int64)data[i-9];
+						sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+						sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+						sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+						sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+						sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+						sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+						sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+						sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+						data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+					}
+				}
+				else { /* order == 11 */
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[10] * (FLAC__int64)data[i-11];
+						sum += qlp_coeff[9] * (FLAC__int64)data[i-10];
+						sum += qlp_coeff[8] * (FLAC__int64)data[i-9];
+						sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+						sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+						sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+						sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+						sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+						sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+						sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+						sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+						data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+					}
+				}
+			}
+			else {
+				if(order == 10) {
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[9] * (FLAC__int64)data[i-10];
+						sum += qlp_coeff[8] * (FLAC__int64)data[i-9];
+						sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+						sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+						sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+						sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+						sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+						sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+						sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+						sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+						data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+					}
+				}
+				else { /* order == 9 */
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[8] * (FLAC__int64)data[i-9];
+						sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+						sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+						sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+						sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+						sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+						sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+						sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+						sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+						data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+					}
+				}
+			}
+		}
+		else if(order > 4) {
+			if(order > 6) {
+				if(order == 8) {
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+						sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+						sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+						sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+						sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+						sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+						sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+						sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+						data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+					}
+				}
+				else { /* order == 7 */
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+						sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+						sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+						sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+						sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+						sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+						sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+						data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+					}
+				}
+			}
+			else {
+				if(order == 6) {
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+						sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+						sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+						sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+						sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+						sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+						data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+					}
+				}
+				else { /* order == 5 */
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+						sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+						sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+						sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+						sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+						data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+					}
+				}
+			}
+		}
+		else {
+			if(order > 2) {
+				if(order == 4) {
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+						sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+						sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+						sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+						data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+					}
+				}
+				else { /* order == 3 */
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+						sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+						sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+						data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+					}
+				}
+			}
+			else {
+				if(order == 2) {
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+						sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+						data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+					}
+				}
+				else { /* order == 1 */
+					for(i = 0; i < (int)data_len; i++)
+						data[i] = residual[i] + (FLAC__int32)((qlp_coeff[0] * (FLAC__int64)data[i-1]) >> lp_quantization);
+				}
+			}
+		}
+	}
+	else { /* order > 12 */
+		for(i = 0; i < (int)data_len; i++) {
+			sum = 0;
+			switch(order) {
+				case 32: sum += qlp_coeff[31] * (FLAC__int64)data[i-32];
+				case 31: sum += qlp_coeff[30] * (FLAC__int64)data[i-31];
+				case 30: sum += qlp_coeff[29] * (FLAC__int64)data[i-30];
+				case 29: sum += qlp_coeff[28] * (FLAC__int64)data[i-29];
+				case 28: sum += qlp_coeff[27] * (FLAC__int64)data[i-28];
+				case 27: sum += qlp_coeff[26] * (FLAC__int64)data[i-27];
+				case 26: sum += qlp_coeff[25] * (FLAC__int64)data[i-26];
+				case 25: sum += qlp_coeff[24] * (FLAC__int64)data[i-25];
+				case 24: sum += qlp_coeff[23] * (FLAC__int64)data[i-24];
+				case 23: sum += qlp_coeff[22] * (FLAC__int64)data[i-23];
+				case 22: sum += qlp_coeff[21] * (FLAC__int64)data[i-22];
+				case 21: sum += qlp_coeff[20] * (FLAC__int64)data[i-21];
+				case 20: sum += qlp_coeff[19] * (FLAC__int64)data[i-20];
+				case 19: sum += qlp_coeff[18] * (FLAC__int64)data[i-19];
+				case 18: sum += qlp_coeff[17] * (FLAC__int64)data[i-18];
+				case 17: sum += qlp_coeff[16] * (FLAC__int64)data[i-17];
+				case 16: sum += qlp_coeff[15] * (FLAC__int64)data[i-16];
+				case 15: sum += qlp_coeff[14] * (FLAC__int64)data[i-15];
+				case 14: sum += qlp_coeff[13] * (FLAC__int64)data[i-14];
+				case 13: sum += qlp_coeff[12] * (FLAC__int64)data[i-13];
+				         sum += qlp_coeff[11] * (FLAC__int64)data[i-12];
+				         sum += qlp_coeff[10] * (FLAC__int64)data[i-11];
+				         sum += qlp_coeff[ 9] * (FLAC__int64)data[i-10];
+				         sum += qlp_coeff[ 8] * (FLAC__int64)data[i- 9];
+				         sum += qlp_coeff[ 7] * (FLAC__int64)data[i- 8];
+				         sum += qlp_coeff[ 6] * (FLAC__int64)data[i- 7];
+				         sum += qlp_coeff[ 5] * (FLAC__int64)data[i- 6];
+				         sum += qlp_coeff[ 4] * (FLAC__int64)data[i- 5];
+				         sum += qlp_coeff[ 3] * (FLAC__int64)data[i- 4];
+				         sum += qlp_coeff[ 2] * (FLAC__int64)data[i- 3];
+				         sum += qlp_coeff[ 1] * (FLAC__int64)data[i- 2];
+				         sum += qlp_coeff[ 0] * (FLAC__int64)data[i- 1];
+			}
+			data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+		}
+	}
+}
+#endif
+
+#if defined(_MSC_VER)
+#pragma warning ( default : 4028 )
+#endif
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+
+FLAC__double FLAC__lpc_compute_expected_bits_per_residual_sample(FLAC__double lpc_error, unsigned total_samples)
 {
-	double error_scale;
+	FLAC__double error_scale;
 
 	FLAC__ASSERT(total_samples > 0);
 
-	error_scale = 0.5 * M_LN2 * M_LN2 / (FLAC__real)total_samples;
+	error_scale = 0.5 * M_LN2 * M_LN2 / (FLAC__double)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)
+FLAC__double FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(FLAC__double lpc_error, FLAC__double error_scale)
 {
 	if(lpc_error > 0.0) {
-		FLAC__real bps = (FLAC__real)((double)0.5 * log(error_scale * lpc_error) / M_LN2);
+		FLAC__double bps = (FLAC__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 if(lpc_error < 0.0) { /* error should not be negative but can happen due to inadequate floating-point resolution */
+		return 1e32;
 	}
 	else {
 		return 0.0;
@@ -397,27 +1332,28 @@
 	}
 }
 
-unsigned FLAC__lpc_compute_best_order(const FLAC__real lpc_error[], unsigned max_order, unsigned total_samples, unsigned bits_per_signal_sample)
+unsigned FLAC__lpc_compute_best_order(const FLAC__double lpc_error[], unsigned max_order, unsigned total_samples, unsigned overhead_bits_per_order)
 {
-	unsigned order, best_order;
-	FLAC__real best_bits, tmp_bits;
-	double error_scale;
+	unsigned order, indx, best_index; /* 'index' the index into lpc_error; index==order-1 since lpc_error[0] is for order==1, lpc_error[1] is for order==2, etc */
+	FLAC__double bits, best_bits, error_scale;
 
 	FLAC__ASSERT(max_order > 0);
 	FLAC__ASSERT(total_samples > 0);
 
-	error_scale = 0.5 * M_LN2 * M_LN2 / (FLAC__real)total_samples;
+	error_scale = 0.5 * M_LN2 * M_LN2 / (FLAC__double)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;
+	best_index = 0;
+	best_bits = (unsigned)(-1);
 
-	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;
+	for(indx = 0, order = 1; indx < max_order; indx++, order++) {
+		bits = FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(lpc_error[indx], error_scale) * (FLAC__double)(total_samples - order) + (FLAC__double)(order * overhead_bits_per_order);
+		if(bits < best_bits) {
+			best_index = indx;
+			best_bits = bits;
 		}
 	}
 
-	return best_order+1; /* +1 since index of lpc_error[] is order-1 */
+	return best_index+1; /* +1 since indx of lpc_error[] is order-1 */
 }
+
+#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */
--- a/sys/src/cmd/audio/libFLAC/md5.c
+++ b/sys/src/cmd/audio/libFLAC/md5.c
@@ -1,3 +1,14 @@
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdlib.h>		/* for malloc() */
+#include <string.h>		/* for memcpy() */
+
+#include "private/md5.h"
+#include "share/alloc.h"
+#include "share/endswap.h"
+
 /*
  * This code implements the MD5 message-digest algorithm.
  * The algorithm is due to Ron Rivest.  This code was
@@ -23,23 +34,6 @@
  * 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) */
@@ -57,9 +51,7 @@
  * 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])
+static void FLAC__MD5Transform(FLAC__uint32 buf[4], FLAC__uint32 const in[16])
 {
 	register FLAC__uint32 a, b, c, d;
 
@@ -142,51 +134,48 @@
 	buf[3] += d;
 }
 
-#endif
-
-FLaC__INLINE
-void
-byteSwap(FLAC__uint32 *buf, unsigned words)
+#if WORDS_BIGENDIAN
+//@@@@@@ OPT: use bswap/intrinsics
+static void byteSwap(FLAC__uint32 *buf, unsigned words)
 {
-	md5byte *p = (md5byte *)buf;
-
-	if(!is_big_endian_host_)
-		return;
+	register FLAC__uint32 x;
 	do {
-		*buf++ = (FLAC__uint32)((unsigned)p[3] << 8 | p[2]) << 16 | ((unsigned)p[1] << 8 | p[0]);
-		p += 4;
+		x = *buf;
+		x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff);
+		*buf++ = (x >> 16) | (x << 16);
 	} while (--words);
 }
-
-/*
- * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
- * initialization constants.
- */
-void
-FLAC__MD5Init(struct FLAC__MD5Context *ctx)
+static void byteSwapX16(FLAC__uint32 *buf)
 {
-	FLAC__uint32 test = 1;
+	register FLAC__uint32 x;
 
-	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;
+	x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
+	x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
+	x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
+	x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
+	x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
+	x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
+	x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
+	x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
+	x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
+	x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
+	x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
+	x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
+	x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
+	x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
+	x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
+	x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf   = (x >> 16) | (x << 16);
 }
+#else
+#define byteSwap(buf, words)
+#define byteSwapX16(buf)
+#endif
 
 /*
  * Update context to reflect the concatenation of another buffer full
  * of bytes.
  */
-void
-FLAC__MD5Update(struct FLAC__MD5Context *ctx, md5byte const *buf, unsigned len)
+static void FLAC__MD5Update(FLAC__MD5Context *ctx, FLAC__byte const *buf, unsigned len)
 {
 	FLAC__uint32 t;
 
@@ -198,12 +187,12 @@
 
 	t = 64 - (t & 0x3f);	/* Space available in ctx->in (at least 1) */
 	if (t > len) {
-		memcpy((md5byte *)ctx->in + 64 - t, buf, len);
+		memcpy((FLAC__byte *)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);
+	memcpy((FLAC__byte *)ctx->in + 64 - t, buf, t);
+	byteSwapX16(ctx->in);
 	FLAC__MD5Transform(ctx->buf, ctx->in);
 	buf += t;
 	len -= t;
@@ -211,7 +200,7 @@
 	/* Process data in 64-byte chunks */
 	while (len >= 64) {
 		memcpy(ctx->in, buf, 64);
-		byteSwap(ctx->in, 16);
+		byteSwapX16(ctx->in);
 		FLAC__MD5Transform(ctx->buf, ctx->in);
 		buf += 64;
 		len -= 64;
@@ -222,55 +211,21 @@
 }
 
 /*
- * Convert the incoming audio signal to a byte stream and FLAC__MD5Update it.
+ * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
+ * initialization constants.
  */
-FLAC__bool
-FLAC__MD5Accumulate(struct FLAC__MD5Context *ctx, const FLAC__int32 * const signal[], unsigned channels, unsigned samples, unsigned bytes_per_sample)
+void FLAC__MD5Init(FLAC__MD5Context *ctx)
 {
-	unsigned channel, sample, a_byte;
-	FLAC__int32 a_word;
-	FLAC__byte *buf_;
-	const unsigned bytes_needed = channels * samples * bytes_per_sample;
+	ctx->buf[0] = 0x67452301;
+	ctx->buf[1] = 0xefcdab89;
+	ctx->buf[2] = 0x98badcfe;
+	ctx->buf[3] = 0x10325476;
 
-	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;
-	}
+	ctx->bytes[0] = 0;
+	ctx->bytes[1] = 0;
 
-	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;
+	ctx->internal_buf.p8= 0;
+	ctx->capacity = 0;
 }
 
 /*
@@ -277,11 +232,10 @@
  * 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)
+void FLAC__MD5Final(FLAC__byte digest[16], FLAC__MD5Context *ctx)
 {
 	int count = ctx->bytes[0] & 0x3f;	/* Number of bytes in ctx->in */
-	md5byte *p = (md5byte *)ctx->in + count;
+	FLAC__byte *p = (FLAC__byte *)ctx->in + count;
 
 	/* Set the first char of padding to 0x80.  There is always room. */
 	*p++ = 0x80;
@@ -291,9 +245,9 @@
 
 	if (count < 0) {	/* Padding forces an extra block */
 		memset(p, 0, count + 8);
-		byteSwap(ctx->in, 16);
+		byteSwapX16(ctx->in);
 		FLAC__MD5Transform(ctx->buf, ctx->in);
-		p = (md5byte *)ctx->in;
+		p = (FLAC__byte *)ctx->in;
 		count = 56;
 	}
 	memset(p, 0, count);
@@ -306,10 +260,259 @@
 
 	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;
+	if (0 != ctx->internal_buf.p8) {
+		free(ctx->internal_buf.p8);
+		ctx->internal_buf.p8= 0;
 		ctx->capacity = 0;
 	}
+	memset(ctx, 0, sizeof(*ctx));	/* In case it's sensitive */
+}
+
+/*
+ * Convert the incoming audio signal to a byte stream
+ */
+static void format_input_(FLAC__multibyte *mbuf, const FLAC__int32 * const signal[], unsigned channels, unsigned samples, unsigned bytes_per_sample)
+{
+	FLAC__byte *buf_ = mbuf->p8;
+	FLAC__int16 *buf16 = mbuf->p16;
+	FLAC__int32 *buf32 = mbuf->p32;
+	FLAC__int32 a_word;
+	unsigned channel, sample;
+
+	/* Storage in the output buffer, buf, is little endian. */
+
+#define BYTES_CHANNEL_SELECTOR(bytes, channels)   (bytes * 100 + channels)
+
+	/* First do the most commonly used combinations. */
+	switch (BYTES_CHANNEL_SELECTOR (bytes_per_sample, channels)) {
+		/* One byte per sample. */
+		case (BYTES_CHANNEL_SELECTOR (1, 1)):
+			for (sample = 0; sample < samples; sample++)
+				*buf_++ = signal[0][sample];
+			return;
+
+		case (BYTES_CHANNEL_SELECTOR (1, 2)):
+			for (sample = 0; sample < samples; sample++) {
+				*buf_++ = signal[0][sample];
+				*buf_++ = signal[1][sample];
+			}
+			return;
+
+		case (BYTES_CHANNEL_SELECTOR (1, 4)):
+			for (sample = 0; sample < samples; sample++) {
+				*buf_++ = signal[0][sample];
+				*buf_++ = signal[1][sample];
+				*buf_++ = signal[2][sample];
+				*buf_++ = signal[3][sample];
+			}
+			return;
+
+		case (BYTES_CHANNEL_SELECTOR (1, 6)):
+			for (sample = 0; sample < samples; sample++) {
+				*buf_++ = signal[0][sample];
+				*buf_++ = signal[1][sample];
+				*buf_++ = signal[2][sample];
+				*buf_++ = signal[3][sample];
+				*buf_++ = signal[4][sample];
+				*buf_++ = signal[5][sample];
+			}
+			return;
+
+		case (BYTES_CHANNEL_SELECTOR (1, 8)):
+			for (sample = 0; sample < samples; sample++) {
+				*buf_++ = signal[0][sample];
+				*buf_++ = signal[1][sample];
+				*buf_++ = signal[2][sample];
+				*buf_++ = signal[3][sample];
+				*buf_++ = signal[4][sample];
+				*buf_++ = signal[5][sample];
+				*buf_++ = signal[6][sample];
+				*buf_++ = signal[7][sample];
+			}
+			return;
+
+		/* Two bytes per sample. */
+		case (BYTES_CHANNEL_SELECTOR (2, 1)):
+			for (sample = 0; sample < samples; sample++)
+				*buf16++ = H2LE_16(signal[0][sample]);
+			return;
+
+		case (BYTES_CHANNEL_SELECTOR (2, 2)):
+			for (sample = 0; sample < samples; sample++) {
+				*buf16++ = H2LE_16(signal[0][sample]);
+				*buf16++ = H2LE_16(signal[1][sample]);
+			}
+			return;
+
+		case (BYTES_CHANNEL_SELECTOR (2, 4)):
+			for (sample = 0; sample < samples; sample++) {
+				*buf16++ = H2LE_16(signal[0][sample]);
+				*buf16++ = H2LE_16(signal[1][sample]);
+				*buf16++ = H2LE_16(signal[2][sample]);
+				*buf16++ = H2LE_16(signal[3][sample]);
+			}
+			return;
+
+		case (BYTES_CHANNEL_SELECTOR (2, 6)):
+			for (sample = 0; sample < samples; sample++) {
+				*buf16++ = H2LE_16(signal[0][sample]);
+				*buf16++ = H2LE_16(signal[1][sample]);
+				*buf16++ = H2LE_16(signal[2][sample]);
+				*buf16++ = H2LE_16(signal[3][sample]);
+				*buf16++ = H2LE_16(signal[4][sample]);
+				*buf16++ = H2LE_16(signal[5][sample]);
+			}
+			return;
+
+		case (BYTES_CHANNEL_SELECTOR (2, 8)):
+			for (sample = 0; sample < samples; sample++) {
+				*buf16++ = H2LE_16(signal[0][sample]);
+				*buf16++ = H2LE_16(signal[1][sample]);
+				*buf16++ = H2LE_16(signal[2][sample]);
+				*buf16++ = H2LE_16(signal[3][sample]);
+				*buf16++ = H2LE_16(signal[4][sample]);
+				*buf16++ = H2LE_16(signal[5][sample]);
+				*buf16++ = H2LE_16(signal[6][sample]);
+				*buf16++ = H2LE_16(signal[7][sample]);
+			}
+			return;
+
+		/* Three bytes per sample. */
+		case (BYTES_CHANNEL_SELECTOR (3, 1)):
+			for (sample = 0; sample < samples; sample++) {
+				a_word = signal[0][sample];
+				*buf_++ = (FLAC__byte)a_word; a_word >>= 8;
+				*buf_++ = (FLAC__byte)a_word; a_word >>= 8;
+				*buf_++ = (FLAC__byte)a_word;
+			}
+			return;
+
+		case (BYTES_CHANNEL_SELECTOR (3, 2)):
+			for (sample = 0; sample < samples; sample++) {
+				a_word = signal[0][sample];
+				*buf_++ = (FLAC__byte)a_word; a_word >>= 8;
+				*buf_++ = (FLAC__byte)a_word; a_word >>= 8;
+				*buf_++ = (FLAC__byte)a_word;
+				a_word = signal[1][sample];
+				*buf_++ = (FLAC__byte)a_word; a_word >>= 8;
+				*buf_++ = (FLAC__byte)a_word; a_word >>= 8;
+				*buf_++ = (FLAC__byte)a_word;
+			}
+			return;
+
+		/* Four bytes per sample. */
+		case (BYTES_CHANNEL_SELECTOR (4, 1)):
+			for (sample = 0; sample < samples; sample++)
+				*buf32++ = H2LE_32(signal[0][sample]);
+			return;
+
+		case (BYTES_CHANNEL_SELECTOR (4, 2)):
+			for (sample = 0; sample < samples; sample++) {
+				*buf32++ = H2LE_32(signal[0][sample]);
+				*buf32++ = H2LE_32(signal[1][sample]);
+			}
+			return;
+
+		case (BYTES_CHANNEL_SELECTOR (4, 4)):
+			for (sample = 0; sample < samples; sample++) {
+				*buf32++ = H2LE_32(signal[0][sample]);
+				*buf32++ = H2LE_32(signal[1][sample]);
+				*buf32++ = H2LE_32(signal[2][sample]);
+				*buf32++ = H2LE_32(signal[3][sample]);
+			}
+			return;
+
+		case (BYTES_CHANNEL_SELECTOR (4, 6)):
+			for (sample = 0; sample < samples; sample++) {
+				*buf32++ = H2LE_32(signal[0][sample]);
+				*buf32++ = H2LE_32(signal[1][sample]);
+				*buf32++ = H2LE_32(signal[2][sample]);
+				*buf32++ = H2LE_32(signal[3][sample]);
+				*buf32++ = H2LE_32(signal[4][sample]);
+				*buf32++ = H2LE_32(signal[5][sample]);
+			}
+			return;
+
+		case (BYTES_CHANNEL_SELECTOR (4, 8)):
+			for (sample = 0; sample < samples; sample++) {
+				*buf32++ = H2LE_32(signal[0][sample]);
+				*buf32++ = H2LE_32(signal[1][sample]);
+				*buf32++ = H2LE_32(signal[2][sample]);
+				*buf32++ = H2LE_32(signal[3][sample]);
+				*buf32++ = H2LE_32(signal[4][sample]);
+				*buf32++ = H2LE_32(signal[5][sample]);
+				*buf32++ = H2LE_32(signal[6][sample]);
+				*buf32++ = H2LE_32(signal[7][sample]);
+			}
+			return;
+
+		default:
+			break;
+	}
+
+	/* General version. */
+	switch (bytes_per_sample) {
+		case 1:
+			for (sample = 0; sample < samples; sample++)
+				for (channel = 0; channel < channels; channel++)
+					*buf_++ = signal[channel][sample];
+			return;
+
+		case 2:
+			for (sample = 0; sample < samples; sample++)
+				for (channel = 0; channel < channels; channel++)
+					*buf16++ = H2LE_16(signal[channel][sample]);
+			return;
+
+		case 3:
+			for (sample = 0; sample < samples; sample++)
+				for (channel = 0; channel < channels; channel++) {
+					a_word = signal[channel][sample];
+					*buf_++ = (FLAC__byte)a_word; a_word >>= 8;
+					*buf_++ = (FLAC__byte)a_word; a_word >>= 8;
+					*buf_++ = (FLAC__byte)a_word;
+				}
+			return;
+
+		case 4:
+			for (sample = 0; sample < samples; sample++)
+				for (channel = 0; channel < channels; channel++)
+					*buf32++ = H2LE_32(signal[channel][sample]);
+			return;
+
+		default:
+			break;
+	}
+}
+
+/*
+ * Convert the incoming audio signal to a byte stream and FLAC__MD5Update it.
+ */
+FLAC__bool FLAC__MD5Accumulate(FLAC__MD5Context *ctx, const FLAC__int32 * const signal[], unsigned channels, unsigned samples, unsigned bytes_per_sample)
+{
+	const size_t bytes_needed = (size_t)channels * (size_t)samples * (size_t)bytes_per_sample;
+
+	/* overflow check */
+	if ((size_t)channels > SIZE_MAX / (size_t)bytes_per_sample)
+		return false;
+	if ((size_t)channels * (size_t)bytes_per_sample > SIZE_MAX / (size_t)samples)
+		return false;
+
+	if (ctx->capacity < bytes_needed) {
+		FLAC__byte *tmp = realloc(ctx->internal_buf.p8, bytes_needed);
+		if (0 == tmp) {
+			free(ctx->internal_buf.p8);
+			if (0 == (ctx->internal_buf.p8= safe_malloc_(bytes_needed)))
+				return false;
+		}
+		else
+			ctx->internal_buf.p8= tmp;
+		ctx->capacity = bytes_needed;
+	}
+
+	format_input_(&ctx->internal_buf, signal, channels, samples, bytes_per_sample);
+
+	FLAC__MD5Update(ctx, ctx->internal_buf.p8, bytes_needed);
+
+	return true;
 }
--- a/sys/src/cmd/audio/libFLAC/memory.c
+++ b/sys/src/cmd/audio/libFLAC/memory.c
@@ -1,5 +1,6 @@
 /* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2001,2002,2003,2004  Josh Coalson
+ * Copyright (C) 2001-2009  Josh Coalson
+ * Copyright (C) 2011-2014  Xiph.Org Foundation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -29,13 +30,18 @@
  * 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>
+#  include <config.h>
 #endif
 
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+
+#include "private/memory.h"
+#include "FLAC/assert.h"
+#include "share/alloc.h"
+
 void *FLAC__memory_alloc_aligned(size_t bytes, void **aligned_address)
 {
 	void *x;
@@ -44,18 +50,22 @@
 
 #ifdef FLAC__ALIGN_MALLOC_DATA
 	/* align on 32-byte (256-bit) boundary */
-	x = malloc(bytes+31);
-	*aligned_address = (void*)(((unsigned)x + 31) & -32);
+	x = safe_malloc_add_2op_(bytes, /*+*/31L);
+	*aligned_address = (void*)(((uintptr_t)x + 31L) & -32L);
 #else
-	x = malloc(bytes);
+	x = safe_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__bool FLAC__memory_alloc_aligned_int32_array(size_t elements, FLAC__int32 **unaligned_pointer, FLAC__int32 **aligned_pointer)
 {
-	FLAC__int32 *pa, *pu; /* aligned pointer, unaligned pointer */
+	FLAC__int32 *pu; /* unaligned pointer */
+	union { /* union needed to comply with C99 pointer aliasing rules */
+		FLAC__int32 *pa; /* aligned pointer */
+		void        *pv; /* aligned pointer alias */
+	} u;
 
 	FLAC__ASSERT(elements > 0);
 	FLAC__ASSERT(0 != unaligned_pointer);
@@ -62,7 +72,10 @@
 	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(elements > SIZE_MAX / sizeof(*pu)) /* overflow check */
+		return false;
+
+	pu = FLAC__memory_alloc_aligned(sizeof(*pu) * elements, &u.pv);
 	if(0 == pu) {
 		return false;
 	}
@@ -70,14 +83,18 @@
 		if(*unaligned_pointer != 0)
 			free(*unaligned_pointer);
 		*unaligned_pointer = pu;
-		*aligned_pointer = pa;
+		*aligned_pointer = u.pa;
 		return true;
 	}
 }
 
-FLAC__bool FLAC__memory_alloc_aligned_uint32_array(unsigned elements, FLAC__uint32 **unaligned_pointer, FLAC__uint32 **aligned_pointer)
+FLAC__bool FLAC__memory_alloc_aligned_uint32_array(size_t elements, FLAC__uint32 **unaligned_pointer, FLAC__uint32 **aligned_pointer)
 {
-	FLAC__uint32 *pa, *pu; /* aligned pointer, unaligned pointer */
+	FLAC__uint32 *pu; /* unaligned pointer */
+	union { /* union needed to comply with C99 pointer aliasing rules */
+		FLAC__uint32 *pa; /* aligned pointer */
+		void         *pv; /* aligned pointer alias */
+	} u;
 
 	FLAC__ASSERT(elements > 0);
 	FLAC__ASSERT(0 != unaligned_pointer);
@@ -84,7 +101,10 @@
 	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(elements > SIZE_MAX / sizeof(*pu)) /* overflow check */
+		return false;
+
+	pu = FLAC__memory_alloc_aligned(sizeof(*pu) * elements, &u.pv);
 	if(0 == pu) {
 		return false;
 	}
@@ -92,14 +112,18 @@
 		if(*unaligned_pointer != 0)
 			free(*unaligned_pointer);
 		*unaligned_pointer = pu;
-		*aligned_pointer = pa;
+		*aligned_pointer = u.pa;
 		return true;
 	}
 }
 
-FLAC__bool FLAC__memory_alloc_aligned_uint64_array(unsigned elements, FLAC__uint64 **unaligned_pointer, FLAC__uint64 **aligned_pointer)
+FLAC__bool FLAC__memory_alloc_aligned_uint64_array(size_t elements, FLAC__uint64 **unaligned_pointer, FLAC__uint64 **aligned_pointer)
 {
-	FLAC__uint64 *pa, *pu; /* aligned pointer, unaligned pointer */
+	FLAC__uint64 *pu; /* unaligned pointer */
+	union { /* union needed to comply with C99 pointer aliasing rules */
+		FLAC__uint64 *pa; /* aligned pointer */
+		void         *pv; /* aligned pointer alias */
+	} u;
 
 	FLAC__ASSERT(elements > 0);
 	FLAC__ASSERT(0 != unaligned_pointer);
@@ -106,7 +130,10 @@
 	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(elements > SIZE_MAX / sizeof(*pu)) /* overflow check */
+		return false;
+
+	pu = FLAC__memory_alloc_aligned(sizeof(*pu) * elements, &u.pv);
 	if(0 == pu) {
 		return false;
 	}
@@ -114,14 +141,18 @@
 		if(*unaligned_pointer != 0)
 			free(*unaligned_pointer);
 		*unaligned_pointer = pu;
-		*aligned_pointer = pa;
+		*aligned_pointer = u.pa;
 		return true;
 	}
 }
 
-FLAC__bool FLAC__memory_alloc_aligned_unsigned_array(unsigned elements, unsigned **unaligned_pointer, unsigned **aligned_pointer)
+FLAC__bool FLAC__memory_alloc_aligned_unsigned_array(size_t elements, unsigned **unaligned_pointer, unsigned **aligned_pointer)
 {
-	unsigned *pa, *pu; /* aligned pointer, unaligned pointer */
+	unsigned *pu; /* unaligned pointer */
+	union { /* union needed to comply with C99 pointer aliasing rules */
+		unsigned *pa; /* aligned pointer */
+		void     *pv; /* aligned pointer alias */
+	} u;
 
 	FLAC__ASSERT(elements > 0);
 	FLAC__ASSERT(0 != unaligned_pointer);
@@ -128,7 +159,10 @@
 	FLAC__ASSERT(0 != aligned_pointer);
 	FLAC__ASSERT(unaligned_pointer != aligned_pointer);
 
-	pu = (unsigned*)FLAC__memory_alloc_aligned(sizeof(unsigned) * elements, (void**)&pa);
+	if(elements > SIZE_MAX / sizeof(*pu)) /* overflow check */
+		return false;
+
+	pu = FLAC__memory_alloc_aligned(sizeof(*pu) * elements, &u.pv);
 	if(0 == pu) {
 		return false;
 	}
@@ -136,14 +170,20 @@
 		if(*unaligned_pointer != 0)
 			free(*unaligned_pointer);
 		*unaligned_pointer = pu;
-		*aligned_pointer = pa;
+		*aligned_pointer = u.pa;
 		return true;
 	}
 }
 
-FLAC__bool FLAC__memory_alloc_aligned_real_array(unsigned elements, FLAC__real **unaligned_pointer, FLAC__real **aligned_pointer)
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+
+FLAC__bool FLAC__memory_alloc_aligned_real_array(size_t elements, FLAC__real **unaligned_pointer, FLAC__real **aligned_pointer)
 {
-	FLAC__real *pa, *pu; /* aligned pointer, unaligned pointer */
+	FLAC__real *pu; /* unaligned pointer */
+	union { /* union needed to comply with C99 pointer aliasing rules */
+		FLAC__real *pa; /* aligned pointer */
+		void       *pv; /* aligned pointer alias */
+	} u;
 
 	FLAC__ASSERT(elements > 0);
 	FLAC__ASSERT(0 != unaligned_pointer);
@@ -150,7 +190,10 @@
 	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(elements > SIZE_MAX / sizeof(*pu)) /* overflow check */
+		return false;
+
+	pu = FLAC__memory_alloc_aligned(sizeof(*pu) * elements, &u.pv);
 	if(0 == pu) {
 		return false;
 	}
@@ -158,7 +201,18 @@
 		if(*unaligned_pointer != 0)
 			free(*unaligned_pointer);
 		*unaligned_pointer = pu;
-		*aligned_pointer = pa;
+		*aligned_pointer = u.pa;
 		return true;
 	}
+}
+
+#endif
+
+void *safe_malloc_mul_2op_p(size_t size1, size_t size2)
+{
+	if(!size1 || !size2)
+		return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */
+	if(size1 > SIZE_MAX / size2)
+		return 0;
+	return malloc(size1*size2);
 }
--- a/sys/src/cmd/audio/libFLAC/metadata_iterators.c
+++ b/sys/src/cmd/audio/libFLAC/metadata_iterators.c
@@ -1,5 +1,6 @@
 /* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2001,2002,2003,2004  Josh Coalson
+ * Copyright (C) 2001-2009  Josh Coalson
+ * Copyright (C) 2011-2014  Xiph.Org Foundation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -29,36 +30,32 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <stdarg.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"
+#include "FLAC/stream_decoder.h"
+#include "share/alloc.h"
+#include "share/compat.h"
+#include "share/macros.h"
+#include "share/safe_str.h"
+#include "private/macros.h"
+#include "private/memory.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))
+/* Alias the first (in share/alloc.h) to the second (in src/libFLAC/memory.c). */
+#define safe_malloc_mul_2op_ safe_malloc_mul_2op_p
 
-
 /****************************************************************************
  *
  * Local function declarations
@@ -80,10 +77,11 @@
 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_vorbis_comment_entry_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_VorbisComment_Entry *entry, unsigned max_length);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata_VorbisComment *block, unsigned block_length);
 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_picture_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Picture *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);
@@ -96,6 +94,7 @@
 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_picture_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Picture *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);
@@ -109,10 +108,10 @@
 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 simple_iterator_copy_file_postfix_(FLAC__Metadata_SimpleIterator *iterator, FILE **tempfile, char **tempfilename, int fixup_is_last_code, FLAC__off_t 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_n_bytes_from_file_(FILE *file, FILE *tempfile, FLAC__off_t bytes, 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, FLAC__off_t bytes, 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);
 
@@ -120,8 +119,8 @@
 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 FLAC__bool get_file_stats_(const char *filename, struct flac_stat_s *stats);
+static void set_file_stats_(const char *filename, struct flac_stat_s *stats);
 
 static int fseek_wrapper_(FLAC__IOHandle handle, FLAC__int64 offset, int whence);
 static FLAC__int64 ftell_wrapper_(FLAC__IOHandle handle);
@@ -147,124 +146,95 @@
  *
  ***************************************************************************/
 
-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);
+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);
 
 typedef struct {
 	FLAC__bool got_error;
-	FLAC__bool got_object;
 	FLAC__StreamMetadata *object;
 } level0_client_data;
 
-FLAC_API FLAC__FileDecoder *FLAC__file_decoder_new(void);
-
-FLAC_API FLAC__bool FLAC__metadata_get_streaminfo(const char *filename, FLAC__StreamMetadata *streaminfo)
+static FLAC__StreamMetadata *get_one_metadata_block_(const char *filename, FLAC__MetadataType type)
 {
 	level0_client_data cd;
-	FLAC__FileDecoder *decoder;
+	FLAC__StreamDecoder *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);
+	decoder = FLAC__stream_decoder_new();
 
-	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(0 == decoder)
+		return 0;
+
+	FLAC__stream_decoder_set_md5_checking(decoder, false);
+	FLAC__stream_decoder_set_metadata_ignore_all(decoder);
+	FLAC__stream_decoder_set_metadata_respond(decoder, type);
+
+	if(FLAC__stream_decoder_init_file(decoder, filename, write_callback_, metadata_callback_, error_callback_, &cd) != FLAC__STREAM_DECODER_INIT_STATUS_OK || cd.got_error) {
+		(void)FLAC__stream_decoder_finish(decoder);
+		FLAC__stream_decoder_delete(decoder);
+		return 0;
 	}
 
-	if(!FLAC__file_decoder_process_until_end_of_metadata(decoder) || cd.got_error) {
-		FLAC__file_decoder_finish(decoder);
-		FLAC__file_decoder_delete(decoder);
+	if(!FLAC__stream_decoder_process_until_end_of_metadata(decoder) || cd.got_error) {
+		(void)FLAC__stream_decoder_finish(decoder);
+		FLAC__stream_decoder_delete(decoder);
 		if(0 != cd.object)
 			FLAC__metadata_object_delete(cd.object);
-		return false;
+		return 0;
 	}
 
-	FLAC__file_decoder_finish(decoder);
-	FLAC__file_decoder_delete(decoder);
+	(void)FLAC__stream_decoder_finish(decoder);
+	FLAC__stream_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;
+	return cd.object;
 }
 
-FLAC_API FLAC__bool FLAC__metadata_get_tags(const char *filename, FLAC__StreamMetadata **tags)
+FLAC_API FLAC__bool FLAC__metadata_get_streaminfo(const char *filename, FLAC__StreamMetadata *streaminfo)
 {
-	level0_client_data cd;
-	FLAC__FileDecoder *decoder;
+	FLAC__StreamMetadata *object;
 
 	FLAC__ASSERT(0 != filename);
-	FLAC__ASSERT(0 != tags);
+	FLAC__ASSERT(0 != streaminfo);
 
-	decoder = FLAC__file_decoder_new();
+	object = get_one_metadata_block_(filename, FLAC__METADATA_TYPE_STREAMINFO);
 
-	if(0 == decoder)
+	if (object) {
+		/* can just copy the contents since STREAMINFO has no internal structure */
+		*streaminfo = *object;
+		FLAC__metadata_object_delete(object);
+		return true;
+	}
+	else {
 		return false;
+	}
+}
 
-	*tags = 0;
+FLAC_API FLAC__bool FLAC__metadata_get_tags(const char *filename, FLAC__StreamMetadata **tags)
+{
+	FLAC__ASSERT(0 != filename);
+	FLAC__ASSERT(0 != tags);
 
-	cd.got_error = false;
-	cd.got_object = false;
-	cd.object = 0;
+	*tags = get_one_metadata_block_(filename, FLAC__METADATA_TYPE_VORBIS_COMMENT);
 
-	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);
+	return 0 != *tags;
+}
 
-	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;
-	}
+FLAC_API FLAC__bool FLAC__metadata_get_cuesheet(const char *filename, FLAC__StreamMetadata **cuesheet)
+{
+	FLAC__ASSERT(0 != filename);
+	FLAC__ASSERT(0 != cuesheet);
 
-	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;
-	}
+	*cuesheet = get_one_metadata_block_(filename, FLAC__METADATA_TYPE_CUESHEET);
 
-	FLAC__file_decoder_finish(decoder);
-	FLAC__file_decoder_delete(decoder);
-
-	if(cd.got_object)
-		*tags = cd.object;
-
-	return cd.got_object;
+	return 0 != *cuesheet;
 }
 
-FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__FileDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
+FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
 {
 	(void)decoder, (void)frame, (void)buffer, (void)client_data;
 
@@ -271,7 +241,7 @@
 	return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
 }
 
-void metadata_callback_(const FLAC__FileDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
+void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
 {
 	level0_client_data *cd = (level0_client_data *)client_data;
 	(void)decoder;
@@ -280,15 +250,13 @@
 	 * we assume we only get here when the one metadata block we were
 	 * looking for was passed to us
 	 */
-	if(!cd->got_object) {
+	if(!cd->got_error && 0 == cd->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)
+void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
 {
 	level0_client_data *cd = (level0_client_data *)client_data;
 	(void)decoder;
@@ -297,7 +265,57 @@
 		cd->got_error = true;
 }
 
+FLAC_API FLAC__bool FLAC__metadata_get_picture(const char *filename, FLAC__StreamMetadata **picture, FLAC__StreamMetadata_Picture_Type type, const char *mime_type, const FLAC__byte *description, unsigned max_width, unsigned max_height, unsigned max_depth, unsigned max_colors)
+{
+	FLAC__Metadata_SimpleIterator *it;
+	FLAC__uint64 max_area_seen = 0;
+	FLAC__uint64 max_depth_seen = 0;
 
+	FLAC__ASSERT(0 != filename);
+	FLAC__ASSERT(0 != picture);
+
+	*picture = 0;
+
+	it = FLAC__metadata_simple_iterator_new();
+	if(0 == it)
+		return false;
+	if(!FLAC__metadata_simple_iterator_init(it, filename, /*read_only=*/true, /*preserve_file_stats=*/true)) {
+		FLAC__metadata_simple_iterator_delete(it);
+		return false;
+	}
+	do {
+		if(FLAC__metadata_simple_iterator_get_block_type(it) == FLAC__METADATA_TYPE_PICTURE) {
+			FLAC__StreamMetadata *obj = FLAC__metadata_simple_iterator_get_block(it);
+			FLAC__uint64 area = (FLAC__uint64)obj->data.picture.width * (FLAC__uint64)obj->data.picture.height;
+			/* check constraints */
+			if(
+				(type == (FLAC__StreamMetadata_Picture_Type)(-1) || type == obj->data.picture.type) &&
+				(mime_type == 0 || !strcmp(mime_type, obj->data.picture.mime_type)) &&
+				(description == 0 || !strcmp((const char *)description, (const char *)obj->data.picture.description)) &&
+				obj->data.picture.width <= max_width &&
+				obj->data.picture.height <= max_height &&
+				obj->data.picture.depth <= max_depth &&
+				obj->data.picture.colors <= max_colors &&
+				(area > max_area_seen || (area == max_area_seen && obj->data.picture.depth > max_depth_seen))
+			) {
+				if(*picture)
+					FLAC__metadata_object_delete(*picture);
+				*picture = obj;
+				max_area_seen = area;
+				max_depth_seen = obj->data.picture.depth;
+			}
+			else {
+				FLAC__metadata_object_delete(obj);
+			}
+		}
+	} while(FLAC__metadata_simple_iterator_next(it));
+
+	FLAC__metadata_simple_iterator_delete(it);
+
+	return (0 != *picture);
+}
+
+
 /****************************************************************************
  *
  * Level 1 implementation
@@ -310,13 +328,12 @@
 struct FLAC__Metadata_SimpleIterator {
 	FILE *file;
 	char *filename, *tempfile_path_prefix;
-	struct stat stats;
+	struct flac_stat_s 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 */
+	FLAC__off_t offset[SIMPLE_ITERATOR_MAX_PUSH_DEPTH];
+	FLAC__off_t 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;
@@ -343,7 +360,7 @@
 
 FLAC_API FLAC__Metadata_SimpleIterator *FLAC__metadata_simple_iterator_new(void)
 {
-	FLAC__Metadata_SimpleIterator *iterator = (FLAC__Metadata_SimpleIterator*)calloc(1, sizeof(FLAC__Metadata_SimpleIterator));
+	FLAC__Metadata_SimpleIterator *iterator = calloc(1, sizeof(FLAC__Metadata_SimpleIterator));
 
 	if(0 != iterator) {
 		iterator->file = 0;
@@ -404,10 +421,10 @@
 
 	FLAC__ASSERT(0 != iterator);
 
-	if(read_only || 0 == (iterator->file = fopen(iterator->filename, "r+b"))) {
+	if(read_only || 0 == (iterator->file = flac_fopen(iterator->filename, "r+b"))) {
 		iterator->is_writable = false;
 		if(read_only || errno == EACCES) {
-			if(0 == (iterator->file = fopen(iterator->filename, "rb"))) {
+			if(0 == (iterator->file = flac_fopen(iterator->filename, "rb"))) {
 				iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE;
 				return false;
 			}
@@ -425,7 +442,7 @@
 	switch(ret) {
 		case 0:
 			iterator->depth = 0;
-			iterator->first_offset = iterator->offset[iterator->depth] = ftell(iterator->file);
+			iterator->first_offset = iterator->offset[iterator->depth] = ftello(iterator->file);
 			return read_metadata_block_header_(iterator);
 		case 1:
 			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
@@ -462,7 +479,7 @@
 
 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 */
+	const char *tempfile_path_prefix = 0; /*@@@ search for comments near 'flac_rename(...)' for what it will take to finish implementing this */
 
 	FLAC__ASSERT(0 != iterator);
 	FLAC__ASSERT(0 != filename);
@@ -500,12 +517,12 @@
 	if(iterator->is_last)
 		return false;
 
-	if(0 != fseek(iterator->file, iterator->length, SEEK_CUR)) {
+	if(0 != fseeko(iterator->file, iterator->length, SEEK_CUR)) {
 		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
 		return false;
 	}
 
-	iterator->offset[iterator->depth] = ftell(iterator->file);
+	iterator->offset[iterator->depth] = ftello(iterator->file);
 
 	return read_metadata_block_header_(iterator);
 }
@@ -512,7 +529,7 @@
 
 FLAC_API FLAC__bool FLAC__metadata_simple_iterator_prev(FLAC__Metadata_SimpleIterator *iterator)
 {
-	long this_offset;
+	FLAC__off_t this_offset;
 
 	FLAC__ASSERT(0 != iterator);
 	FLAC__ASSERT(0 != iterator->file);
@@ -520,7 +537,7 @@
 	if(iterator->offset[iterator->depth] == iterator->first_offset)
 		return false;
 
-	if(0 != fseek(iterator->file, iterator->first_offset, SEEK_SET)) {
+	if(0 != fseeko(iterator->file, iterator->first_offset, SEEK_SET)) {
 		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
 		return false;
 	}
@@ -528,13 +545,13 @@
 	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)) {
+	/* we ignore any error from ftello() and catch it in fseeko() */
+	while(ftello(iterator->file) + (FLAC__off_t)iterator->length < iterator->offset[iterator->depth]) {
+		if(0 != fseeko(iterator->file, iterator->length, SEEK_CUR)) {
 			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
 			return false;
 		}
-		this_offset = ftell(iterator->file);
+		this_offset = ftello(iterator->file);
 		if(!read_metadata_block_header_(iterator))
 			return false;
 	}
@@ -544,6 +561,24 @@
 	return true;
 }
 
+/*@@@@add to tests*/
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_is_last(const FLAC__Metadata_SimpleIterator *iterator)
+{
+	FLAC__ASSERT(0 != iterator);
+	FLAC__ASSERT(0 != iterator->file);
+
+	return iterator->is_last;
+}
+
+/*@@@@add to tests*/
+FLAC_API off_t FLAC__metadata_simple_iterator_get_block_offset(const FLAC__Metadata_SimpleIterator *iterator)
+{
+	FLAC__ASSERT(0 != iterator);
+	FLAC__ASSERT(0 != iterator->file);
+
+	return iterator->offset[iterator->depth];
+}
+
 FLAC_API FLAC__MetadataType FLAC__metadata_simple_iterator_get_block_type(const FLAC__Metadata_SimpleIterator *iterator)
 {
 	FLAC__ASSERT(0 != iterator);
@@ -552,6 +587,43 @@
 	return iterator->type;
 }
 
+/*@@@@add to tests*/
+FLAC_API unsigned FLAC__metadata_simple_iterator_get_block_length(const FLAC__Metadata_SimpleIterator *iterator)
+{
+	FLAC__ASSERT(0 != iterator);
+	FLAC__ASSERT(0 != iterator->file);
+
+	return iterator->length;
+}
+
+/*@@@@add to tests*/
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_get_application_id(FLAC__Metadata_SimpleIterator *iterator, FLAC__byte *id)
+{
+	const unsigned id_bytes = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8;
+
+	FLAC__ASSERT(0 != iterator);
+	FLAC__ASSERT(0 != iterator->file);
+	FLAC__ASSERT(0 != id);
+
+	if(iterator->type != FLAC__METADATA_TYPE_APPLICATION) {
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT;
+		return false;
+	}
+
+	if(fread(id, 1, id_bytes, iterator->file) != id_bytes) {
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+		return false;
+	}
+
+	/* back up */
+	if(0 != fseeko(iterator->file, -((int)id_bytes), SEEK_CUR)) {
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+		return false;
+	}
+
+	return true;
+}
+
 FLAC_API FLAC__StreamMetadata *FLAC__metadata_simple_iterator_get_block(FLAC__Metadata_SimpleIterator *iterator)
 {
 	FLAC__StreamMetadata *block = FLAC__metadata_object_new(iterator->type);
@@ -569,7 +641,7 @@
 		}
 
 		/* 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)) {
+		if(0 != fseeko(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;
@@ -583,7 +655,7 @@
 
 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__ASSERT_DECLARATION(FLAC__off_t debug_target_offset = iterator->offset[iterator->depth];)
 	FLAC__bool ret;
 
 	FLAC__ASSERT(0 != iterator);
@@ -610,13 +682,13 @@
 		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);
+			FLAC__ASSERT(!ret || ftello(iterator->file) == debug_target_offset + (FLAC__off_t)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);
+			FLAC__ASSERT(!ret || ftello(iterator->file) == debug_target_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
 			return ret;
 		}
 	}
@@ -659,7 +731,7 @@
 			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);
+				FLAC__ASSERT(!ret || ftello(iterator->file) == debug_target_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
 				return ret;
 			}
 			else {
@@ -666,7 +738,7 @@
 				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);
+				FLAC__ASSERT(!ret || ftello(iterator->file) == debug_target_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
 				return ret;
 			}
 		}
@@ -673,7 +745,7 @@
 		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);
+			FLAC__ASSERT(!ret || ftello(iterator->file) == debug_target_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
 			return ret;
 		}
 	}
@@ -684,7 +756,7 @@
 	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__ASSERT_DECLARATION(FLAC__off_t debug_target_offset = iterator->offset[iterator->depth] + FLAC__STREAM_METADATA_HEADER_LENGTH + iterator->length;)
 	FLAC__bool ret;
 
 	FLAC__ASSERT(0 != iterator);
@@ -691,8 +763,10 @@
 	FLAC__ASSERT(0 != iterator->file);
 	FLAC__ASSERT(0 != block);
 
-	if(!iterator->is_writable)
+	if(!iterator->is_writable) {
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE;
 		return false;
+	}
 
 	if(block->type == FLAC__METADATA_TYPE_STREAMINFO) {
 		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT;
@@ -739,7 +813,7 @@
 		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);
+			FLAC__ASSERT(ftello(iterator->file) == debug_target_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
 			return ret;
 		}
 		else {
@@ -746,7 +820,7 @@
 			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);
+			FLAC__ASSERT(ftello(iterator->file) == debug_target_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
 			return ret;
 		}
 	}
@@ -753,7 +827,7 @@
 	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);
+		FLAC__ASSERT(ftello(iterator->file) == debug_target_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
 		return ret;
 	}
 }
@@ -760,7 +834,7 @@
 
 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__ASSERT_DECLARATION(FLAC__off_t debug_target_offset = iterator->offset[iterator->depth];)
 	FLAC__bool ret;
 
 	if(iterator->type == FLAC__METADATA_TYPE_STREAMINFO) {
@@ -782,14 +856,14 @@
 		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);
+		FLAC__ASSERT(iterator->offset[iterator->depth] + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH + (FLAC__off_t)iterator->length == debug_target_offset);
+		FLAC__ASSERT(ftello(iterator->file) + (FLAC__off_t)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);
+		FLAC__ASSERT(iterator->offset[iterator->depth] + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH + (FLAC__off_t)iterator->length == debug_target_offset);
+		FLAC__ASSERT(ftello(iterator->file) + (FLAC__off_t)iterator->length == debug_target_offset);
 		return ret;
 	}
 }
@@ -810,17 +884,21 @@
 
 struct FLAC__Metadata_Chain {
 	char *filename; /* will be NULL if using callbacks */
+	FLAC__bool is_ogg;
 	FLAC__Metadata_Node *head;
 	FLAC__Metadata_Node *tail;
 	unsigned nodes;
 	FLAC__Metadata_ChainStatus status;
-	long first_offset, last_offset; /*@@@ 2G limit */
+	FLAC__off_t first_offset, last_offset;
 	/*
 	 * 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 */
+	FLAC__off_t initial_length;
+	/* @@@ hacky, these are currently only needed by ogg reader */
+	FLAC__IOHandle handle;
+	FLAC__IOCallback_Read read_cb;
 };
 
 struct FLAC__Metadata_Iterator {
@@ -850,7 +928,7 @@
 
 static FLAC__Metadata_Node *node_new_(void)
 {
-	return (FLAC__Metadata_Node*)calloc(1, sizeof(FLAC__Metadata_Node));
+	return calloc(1, sizeof(FLAC__Metadata_Node));
 }
 
 static void node_delete_(FLAC__Metadata_Node *node)
@@ -866,10 +944,12 @@
 	FLAC__ASSERT(0 != chain);
 
 	chain->filename = 0;
+	chain->is_ogg = false;
 	chain->head = chain->tail = 0;
 	chain->nodes = 0;
 	chain->status = FLAC__METADATA_CHAIN_STATUS_OK;
 	chain->initial_length = 0;
+	chain->read_cb = 0;
 }
 
 static void chain_clear_(FLAC__Metadata_Chain *chain)
@@ -939,10 +1019,10 @@
 	node_delete_(node);
 }
 
-static unsigned chain_calculate_length_(FLAC__Metadata_Chain *chain)
+static FLAC__off_t chain_calculate_length_(FLAC__Metadata_Chain *chain)
 {
 	const FLAC__Metadata_Node *node;
-	unsigned length = 0;
+	FLAC__off_t length = 0;
 	for(node = chain->head; node; node = node->next)
 		length += (FLAC__STREAM_METADATA_HEADER_LENGTH + node->data->length);
 	return length;
@@ -1021,20 +1101,20 @@
 /* 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)
+static FLAC__off_t chain_prepare_for_write_(FLAC__Metadata_Chain *chain, FLAC__bool use_padding)
 {
-	unsigned current_length = chain_calculate_length_(chain);
+	FLAC__off_t 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;
+			const FLAC__off_t 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) {
+		else if(current_length + (FLAC__off_t)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))) {
@@ -1054,16 +1134,16 @@
 		}
 		/* 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;
+			const FLAC__off_t 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) {
+				if((FLAC__off_t)chain->tail->data->length + (FLAC__off_t)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) {
+				else if((FLAC__off_t)chain->tail->data->length >= delta) {
 					chain->tail->data->length -= delta;
 					current_length -= delta;
 					FLAC__ASSERT(current_length == chain->initial_length);
@@ -1106,7 +1186,7 @@
 			chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR;
 			return false;
 		}
-		chain->first_offset = (long)pos;
+		chain->first_offset = (FLAC__off_t)pos;
 	}
 
 	{
@@ -1122,6 +1202,7 @@
 			}
 
 			if(!read_metadata_block_header_cb_(handle, read_cb, &is_last, &type, &length)) {
+				node_delete_(node);
 				chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR;
 				return false;
 			}
@@ -1151,7 +1232,7 @@
 			chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR;
 			return false;
 		}
-		chain->last_offset = (long)pos;
+		chain->last_offset = (FLAC__off_t)pos;
 	}
 
 	chain->initial_length = chain_calculate_length_(chain);
@@ -1159,6 +1240,96 @@
 	return true;
 }
 
+static FLAC__StreamDecoderReadStatus chain_read_ogg_read_cb_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
+{
+	FLAC__Metadata_Chain *chain = (FLAC__Metadata_Chain*)client_data;
+	(void)decoder;
+	if(*bytes > 0 && chain->status == FLAC__METADATA_CHAIN_STATUS_OK) {
+		*bytes = chain->read_cb(buffer, sizeof(FLAC__byte), *bytes, chain->handle);
+		if(*bytes == 0)
+			return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+		else
+			return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+	}
+	else
+		return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+}
+
+static FLAC__StreamDecoderWriteStatus chain_read_ogg_write_cb_(const FLAC__StreamDecoder *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_ABORT;
+}
+
+static void chain_read_ogg_metadata_cb_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
+{
+	FLAC__Metadata_Chain *chain = (FLAC__Metadata_Chain*)client_data;
+	FLAC__Metadata_Node *node;
+
+	(void)decoder;
+
+	node = node_new_();
+	if(0 == node) {
+		chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
+		return;
+	}
+
+	node->data = FLAC__metadata_object_clone(metadata);
+	if(0 == node->data) {
+		node_delete_(node);
+		chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
+		return;
+	}
+
+	chain_append_node_(chain, node);
+}
+
+static void chain_read_ogg_error_cb_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+	FLAC__Metadata_Chain *chain = (FLAC__Metadata_Chain*)client_data;
+	(void)decoder, (void)status;
+	chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR; /*@@@ maybe needs better error code */
+}
+
+static FLAC__bool chain_read_ogg_cb_(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb)
+{
+	FLAC__StreamDecoder *decoder;
+
+	FLAC__ASSERT(0 != chain);
+
+	/* we assume we're already at the beginning of the file */
+
+	chain->handle = handle;
+	chain->read_cb = read_cb;
+	if(0 == (decoder = FLAC__stream_decoder_new())) {
+		chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
+		return false;
+	}
+	FLAC__stream_decoder_set_metadata_respond_all(decoder);
+	if(FLAC__stream_decoder_init_ogg_stream(decoder, chain_read_ogg_read_cb_, /*seek_callback=*/0, /*tell_callback=*/0, /*length_callback=*/0, /*eof_callback=*/0, chain_read_ogg_write_cb_, chain_read_ogg_metadata_cb_, chain_read_ogg_error_cb_, chain) != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
+		FLAC__stream_decoder_delete(decoder);
+		chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR; /*@@@ maybe needs better error code */
+		return false;
+	}
+
+	chain->first_offset = 0; /*@@@ wrong; will need to be set correctly to implement metadata writing for Ogg FLAC */
+
+	if(!FLAC__stream_decoder_process_until_end_of_metadata(decoder))
+		chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR; /*@@@ maybe needs better error code */
+	if(chain->status != FLAC__METADATA_CHAIN_STATUS_OK) {
+		FLAC__stream_decoder_delete(decoder);
+		return false;
+	}
+
+	FLAC__stream_decoder_delete(decoder);
+
+	chain->last_offset = 0; /*@@@ wrong; will need to be set correctly to implement metadata writing for Ogg FLAC */
+
+	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;
@@ -1182,7 +1353,7 @@
 		}
 	}
 
-	/*FLAC__ASSERT(fflush(), ftell() == chain->last_offset);*/
+	/*FLAC__ASSERT(fflush(), ftello() == chain->last_offset);*/
 
 	chain->status = FLAC__METADATA_CHAIN_STATUS_OK;
 	return true;
@@ -1195,7 +1366,7 @@
 
 	FLAC__ASSERT(0 != chain->filename);
 
-	if(0 == (file = fopen(chain->filename, "r+b"))) {
+	if(0 == (file = flac_fopen(chain->filename, "r+b"))) {
 		chain->status = FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE;
 		return false;
 	}
@@ -1210,7 +1381,7 @@
 
 static FLAC__bool chain_rewrite_file_(FLAC__Metadata_Chain *chain, const char *tempfile_path_prefix)
 {
-	FILE *f, *tempfile;
+	FILE *f, *tempfile = NULL;
 	char *tempfilename;
 	FLAC__Metadata_SimpleIteratorStatus status;
 	const FLAC__Metadata_Node *node;
@@ -1220,19 +1391,17 @@
 	FLAC__ASSERT(0 != chain->head);
 
 	/* copy the file prefix (data up to first metadata block */
-	if(0 == (f = fopen(chain->filename, "rb"))) {
+	if(0 == (f = flac_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;
+		goto err;
 	}
 	if(!copy_n_bytes_from_file_(f, tempfile, chain->first_offset, &status)) {
 		chain->status = get_equivalent_status_(status);
-		cleanup_tempfile_(&tempfile, &tempfilename);
-		return false;
+		goto err;
 	}
 
 	/* write the metadata */
@@ -1239,25 +1408,23 @@
 	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;
+			goto err;
 		}
 		if(!write_metadata_block_data_(tempfile, &status, node->data)) {
 			chain->status = get_equivalent_status_(status);
-			return false;
+			goto err;
 		}
 	}
-	/*FLAC__ASSERT(fflush(), ftell() == chain->last_offset);*/
+	/*FLAC__ASSERT(fflush(), ftello() == chain->last_offset);*/
 
 	/* copy the file postfix (everything after the metadata) */
-	if(0 != fseek(f, chain->last_offset, SEEK_SET)) {
-		cleanup_tempfile_(&tempfile, &tempfilename);
+	if(0 != fseeko(f, chain->last_offset, SEEK_SET)) {
 		chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
-		return false;
+		goto err;
 	}
 	if(!copy_remaining_bytes_from_file_(f, tempfile, &status)) {
-		cleanup_tempfile_(&tempfile, &tempfilename);
 		chain->status = get_equivalent_status_(status);
-		return false;
+		goto err;
 	}
 
 	/* move the tempfile on top of the original */
@@ -1266,6 +1433,11 @@
 		return false;
 
 	return true;
+
+err:
+	(void)fclose(f);
+	cleanup_tempfile_(&tempfile, &tempfilename);
+	return false;
 }
 
 /* assumes 'handle' is already at beginning of file */
@@ -1295,7 +1467,7 @@
 			return false;
 		}
 	}
-	/*FLAC__ASSERT(fflush(), ftell() == chain->last_offset);*/
+	/*FLAC__ASSERT(fflush(), ftello() == chain->last_offset);*/
 
 	/* copy the file postfix (everything after the metadata) */
 	if(0 != seek_cb(handle, chain->last_offset, SEEK_SET)) {
@@ -1310,9 +1482,9 @@
 	return true;
 }
 
-FLAC_API FLAC__Metadata_Chain *FLAC__metadata_chain_new()
+FLAC_API FLAC__Metadata_Chain *FLAC__metadata_chain_new(void)
 {
-	FLAC__Metadata_Chain *chain = (FLAC__Metadata_Chain*)calloc(1, sizeof(FLAC__Metadata_Chain));
+	FLAC__Metadata_Chain *chain = calloc(1, sizeof(FLAC__Metadata_Chain));
 
 	if(0 != chain)
 		chain_init_(chain);
@@ -1340,7 +1512,7 @@
 	return status;
 }
 
-FLAC_API FLAC__bool FLAC__metadata_chain_read(FLAC__Metadata_Chain *chain, const char *filename)
+static FLAC__bool chain_read_(FLAC__Metadata_Chain *chain, const char *filename, FLAC__bool is_ogg)
 {
 	FILE *file;
 	FLAC__bool ret;
@@ -1355,13 +1527,18 @@
 		return false;
 	}
 
-	if(0 == (file = fopen(filename, "rb"))) {
+	chain->is_ogg = is_ogg;
+
+	if(0 == (file = flac_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_);
+	/* the function also sets chain->status for us */
+	ret = is_ogg?
+		chain_read_ogg_cb_(chain, file, (FLAC__IOCallback_Read)fread) :
+		chain_read_cb_(chain, file, (FLAC__IOCallback_Read)fread, fseek_wrapper_, ftell_wrapper_)
+	;
 
 	fclose(file);
 
@@ -1368,8 +1545,21 @@
 	return ret;
 }
 
-FLAC_API FLAC__bool FLAC__metadata_chain_read_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks)
+FLAC_API FLAC__bool FLAC__metadata_chain_read(FLAC__Metadata_Chain *chain, const char *filename)
 {
+	return chain_read_(chain, filename, /*is_ogg=*/false);
+}
+
+/*@@@@add to tests*/
+FLAC_API FLAC__bool FLAC__metadata_chain_read_ogg(FLAC__Metadata_Chain *chain, const char *filename)
+{
+	return chain_read_(chain, filename, /*is_ogg=*/true);
+}
+
+static FLAC__bool chain_read_with_callbacks_(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks, FLAC__bool is_ogg)
+{
+	FLAC__bool ret;
+
 	FLAC__ASSERT(0 != chain);
 
 	chain_clear_(chain);
@@ -1379,6 +1569,8 @@
 		return false;
 	}
 
+	chain->is_ogg = is_ogg;
+
 	/* rewind */
 	if(0 != callbacks.seek(handle, 0, SEEK_SET)) {
 		chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
@@ -1385,12 +1577,26 @@
 		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_ */
+	/* the function also sets chain->status for us */
+	ret = is_ogg?
+		chain_read_ogg_cb_(chain, handle, callbacks.read) :
+		chain_read_cb_(chain, handle, callbacks.read, callbacks.seek, callbacks.tell)
+	;
 
-	return true;
+	return ret;
 }
 
+FLAC_API FLAC__bool FLAC__metadata_chain_read_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks)
+{
+	return chain_read_with_callbacks_(chain, handle, callbacks, /*is_ogg=*/false);
+}
+
+/*@@@@add to tests*/
+FLAC_API FLAC__bool FLAC__metadata_chain_read_ogg_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks)
+{
+	return chain_read_with_callbacks_(chain, handle, callbacks, /*is_ogg=*/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_()
@@ -1397,7 +1603,7 @@
 	 * 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);
+	const FLAC__off_t current_length = chain_calculate_length_(chain);
 
 	FLAC__ASSERT(0 != chain);
 
@@ -1406,17 +1612,17 @@
 		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)
+		else if(current_length + (FLAC__off_t)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;
+			const FLAC__off_t 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)
+				if((FLAC__off_t)chain->tail->data->length + (FLAC__off_t)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)
+				else if((FLAC__off_t)chain->tail->data->length >= delta)
 					return false;
 			}
 		}
@@ -1427,12 +1633,17 @@
 
 FLAC_API FLAC__bool FLAC__metadata_chain_write(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__bool preserve_file_stats)
 {
-	struct stat stats;
+	struct flac_stat_s stats;
 	const char *tempfile_path_prefix = 0;
-	unsigned current_length;
+	FLAC__off_t current_length;
 
 	FLAC__ASSERT(0 != chain);
 
+	if (chain->is_ogg) { /* cannot write back to Ogg FLAC yet */
+		chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR;
+		return false;
+	}
+
 	if (0 == chain->filename) {
 		chain->status = FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH;
 		return false;
@@ -1473,10 +1684,15 @@
 
 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__off_t current_length;
 
 	FLAC__ASSERT(0 != chain);
 
+	if (chain->is_ogg) { /* cannot write back to Ogg FLAC yet */
+		chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR;
+		return false;
+	}
+
 	if (0 != chain->filename) {
 		chain->status = FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH;
 		return false;
@@ -1505,10 +1721,15 @@
 
 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__off_t current_length;
 
 	FLAC__ASSERT(0 != chain);
 
+	if (chain->is_ogg) { /* cannot write back to Ogg FLAC yet */
+		chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR;
+		return false;
+	}
+
 	if (0 != chain->filename) {
 		chain->status = FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH;
 		return false;
@@ -1596,9 +1817,9 @@
 }
 
 
-FLAC_API FLAC__Metadata_Iterator *FLAC__metadata_iterator_new()
+FLAC_API FLAC__Metadata_Iterator *FLAC__metadata_iterator_new(void)
 {
-	FLAC__Metadata_Iterator *iterator = (FLAC__Metadata_Iterator*)calloc(1, sizeof(FLAC__Metadata_Iterator));
+	FLAC__Metadata_Iterator *iterator = calloc(1, sizeof(FLAC__Metadata_Iterator));
 
 	/* calloc() implies:
 		iterator->current = 0;
@@ -1872,9 +2093,11 @@
 		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);
+			return read_metadata_block_data_vorbis_comment_cb_(handle, read_cb, seek_cb, &block->data.vorbis_comment, block->length);
 		case FLAC__METADATA_TYPE_CUESHEET:
 			return read_metadata_block_data_cuesheet_cb_(handle, read_cb, &block->data.cue_sheet);
+		case FLAC__METADATA_TYPE_PICTURE:
+			return read_metadata_block_data_picture_cb_(handle, read_cb, &block->data.picture);
 		default:
 			return read_metadata_block_data_unknown_cb_(handle, read_cb, &block->data.unknown, block->length);
 	}
@@ -1906,7 +2129,6 @@
 	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 */
@@ -1924,6 +2146,9 @@
 	if(read_cb(block->id, 1, id_bytes, handle) != id_bytes)
 		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
 
+	if(block_length < id_bytes)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+
 	block_length -= id_bytes;
 
 	if(block_length == 0) {
@@ -1930,7 +2155,7 @@
 		block->data = 0;
 	}
 	else {
-		if(0 == (block->data = (FLAC__byte*)malloc(block_length)))
+		if(0 == (block->data = malloc(block_length)))
 			return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
 
 		if(read_cb(block->data, 1, block_length, handle) != block_length)
@@ -1951,7 +2176,7 @@
 
 	if(block->num_points == 0)
 		block->points = 0;
-	else if(0 == (block->points = (FLAC__StreamMetadata_SeekPoint*)malloc(block->num_points * sizeof(FLAC__StreamMetadata_SeekPoint))))
+	else if(0 == (block->points = safe_malloc_mul_2op_p(block->num_points, /*times*/sizeof(FLAC__StreamMetadata_SeekPoint))))
 		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
 
 	for(i = 0; i < block->num_points; i++) {
@@ -1966,16 +2191,24 @@
 	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)
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_entry_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_VorbisComment_Entry *entry, unsigned max_length)
 {
 	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);
+	FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8 == sizeof(buffer));
 
+	if(max_length < entry_length_len)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA;
+
+	max_length -= entry_length_len;
 	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(max_length < entry->length) {
+		entry->length = 0;
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA;
+	} else max_length -= entry->length;
 
 	if(0 != entry->entry)
 		free(entry->entry);
@@ -1984,17 +2217,19 @@
 		entry->entry = 0;
 	}
 	else {
-		if(0 == (entry->entry = (FLAC__byte*)malloc(entry->length)))
+		if(0 == (entry->entry = safe_malloc_add_2op_(entry->length, /*+*/1)))
 			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;
+
+		entry->entry[entry->length] = '\0';
 	}
 
 	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)
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata_VorbisComment *block, unsigned block_length)
 {
 	unsigned i;
 	FLAC__Metadata_SimpleIteratorStatus status;
@@ -2001,11 +2236,18 @@
 	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);
+	FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN / 8 == sizeof(buffer));
 
-	if(FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK != (status = read_metadata_block_data_vorbis_comment_entry_cb_(handle, read_cb, &(block->vendor_string))))
+	status = read_metadata_block_data_vorbis_comment_entry_cb_(handle, read_cb, &(block->vendor_string), block_length);
+	if(block_length >= 4)
+		block_length -= 4;
+	if(status == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA)
+		goto skip;
+	else if(status != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK)
 		return status;
+	block_length -= block->vendor_string.length;
 
+	if(block_length < num_comments_len) goto skip; else block_length -= num_comments_len;
 	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);
@@ -2013,14 +2255,27 @@
 	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))))
+	else if(0 == (block->comments = 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;
+		status = read_metadata_block_data_vorbis_comment_entry_cb_(handle, read_cb, block->comments + i, block_length);
+		if(block_length >= 4) block_length -= 4;
+		if(status == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA) {
+			block->num_comments = i;
+			goto skip;
+		}
+		else if(status != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK) return status;
+		block_length -= block->comments[i].length;
 	}
 
+  skip:
+	if(block_length > 0) {
+		/* bad metadata */
+		if(0 != seek_cb(handle, block_length, SEEK_CUR))
+			return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+	}
+
 	return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
 }
 
@@ -2068,7 +2323,7 @@
 	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))))
+	else if(0 == (track->indices = 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++) {
@@ -2128,7 +2383,7 @@
 	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))))
+	else if(0 == (block->tracks = 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++) {
@@ -2139,6 +2394,92 @@
 	return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
 }
 
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_picture_cstring_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__byte **data, FLAC__uint32 *length, FLAC__uint32 length_len)
+{
+	FLAC__byte buffer[sizeof(FLAC__uint32)];
+
+	FLAC__ASSERT(0 != data);
+	FLAC__ASSERT(length_len%8 == 0);
+
+	length_len /= 8; /* convert to bytes */
+
+	FLAC__ASSERT(sizeof(buffer) >= length_len);
+
+	if(read_cb(buffer, 1, length_len, handle) != length_len)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	*length = unpack_uint32_(buffer, length_len);
+
+	if(0 != *data)
+		free(*data);
+
+	if(0 == (*data = safe_malloc_add_2op_(*length, /*+*/1)))
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+	if(*length > 0) {
+		if(read_cb(*data, 1, *length, handle) != *length)
+			return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	}
+
+	(*data)[*length] = '\0';
+
+	return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_picture_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Picture *block)
+{
+	FLAC__Metadata_SimpleIteratorStatus status;
+	FLAC__byte buffer[4]; /* asserted below that this is big enough */
+	FLAC__uint32 len;
+
+	FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_TYPE_LEN/8);
+	FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN/8);
+	FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN/8);
+	FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN/8);
+	FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_COLORS_LEN/8);
+
+	FLAC__ASSERT(FLAC__STREAM_METADATA_PICTURE_TYPE_LEN % 8 == 0);
+	len = FLAC__STREAM_METADATA_PICTURE_TYPE_LEN / 8;
+	if(read_cb(buffer, 1, len, handle) != len)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	block->type = (FLAC__StreamMetadata_Picture_Type)unpack_uint32_(buffer, len);
+
+	if((status = read_metadata_block_data_picture_cstring_cb_(handle, read_cb, (FLAC__byte**)(&(block->mime_type)), &len, FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN)) != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK)
+		return status;
+
+	if((status = read_metadata_block_data_picture_cstring_cb_(handle, read_cb, &(block->description), &len, FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN)) != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK)
+		return status;
+
+	FLAC__ASSERT(FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN % 8 == 0);
+	len = FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN / 8;
+	if(read_cb(buffer, 1, len, handle) != len)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	block->width = unpack_uint32_(buffer, len);
+
+	FLAC__ASSERT(FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN % 8 == 0);
+	len = FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN / 8;
+	if(read_cb(buffer, 1, len, handle) != len)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	block->height = unpack_uint32_(buffer, len);
+
+	FLAC__ASSERT(FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN % 8 == 0);
+	len = FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN / 8;
+	if(read_cb(buffer, 1, len, handle) != len)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	block->depth = unpack_uint32_(buffer, len);
+
+	FLAC__ASSERT(FLAC__STREAM_METADATA_PICTURE_COLORS_LEN % 8 == 0);
+	len = FLAC__STREAM_METADATA_PICTURE_COLORS_LEN / 8;
+	if(read_cb(buffer, 1, len, handle) != len)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	block->colors = unpack_uint32_(buffer, len);
+
+	/* for convenience we use read_metadata_block_data_picture_cstring_cb_() even though it adds an extra terminating NUL we don't use */
+	if((status = read_metadata_block_data_picture_cstring_cb_(handle, read_cb, &(block->data), &(block->data_length), FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN)) != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK)
+		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) {
@@ -2145,7 +2486,7 @@
 		block->data = 0;
 	}
 	else {
-		if(0 == (block->data = (FLAC__byte*)malloc(block_length)))
+		if(0 == (block->data = malloc(block_length)))
 			return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
 
 		if(read_cb(block->data, 1, block_length, handle) != block_length)
@@ -2215,6 +2556,8 @@
 			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);
+		case FLAC__METADATA_TYPE_PICTURE:
+			return write_metadata_block_data_picture_cb_(handle, write_cb, &block->data.picture);
 		default:
 			return write_metadata_block_data_unknown_cb_(handle, write_cb, &block->data.unknown, block->length);
 	}
@@ -2307,7 +2650,7 @@
 	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);
+	FLAC__ASSERT(flac_max(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN, FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN) / 8 == sizeof(buffer));
 
 	pack_uint32_little_endian_(block->vendor_string.length, buffer, entry_length_len);
 	if(write_cb(buffer, 1, entry_length_len, handle) != entry_length_len)
@@ -2399,17 +2742,17 @@
 			return false;
 
 		for(j = 0; j < track->num_indices; j++) {
-			FLAC__StreamMetadata_CueSheet_Index *index = track->indices + j;
+			FLAC__StreamMetadata_CueSheet_Index *indx = 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);
+			pack_uint64_(indx->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);
+			pack_uint32_(indx->number, buffer, len);
 			if(write_cb(buffer, 1, len, handle) != len)
 				return false;
 
@@ -2424,6 +2767,80 @@
 	return true;
 }
 
+FLAC__bool write_metadata_block_data_picture_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Picture *block)
+{
+	unsigned len;
+	size_t slen;
+	FLAC__byte buffer[4]; /* magic number is asserted below */
+
+	FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_TYPE_LEN%8);
+	FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN%8);
+	FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN%8);
+	FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN%8);
+	FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN%8);
+	FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN%8);
+	FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_COLORS_LEN%8);
+	FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN%8);
+	FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_TYPE_LEN/8);
+	FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN/8);
+	FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN/8);
+	FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN/8);
+	FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN/8);
+	FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN/8);
+	FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_COLORS_LEN/8);
+	FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN/8);
+
+	len = FLAC__STREAM_METADATA_PICTURE_TYPE_LEN/8;
+	pack_uint32_(block->type, buffer, len);
+	if(write_cb(buffer, 1, len, handle) != len)
+		return false;
+
+	len = FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN/8;
+	slen = strlen(block->mime_type);
+	pack_uint32_(slen, buffer, len);
+	if(write_cb(buffer, 1, len, handle) != len)
+		return false;
+	if(write_cb(block->mime_type, 1, slen, handle) != slen)
+		return false;
+
+	len = FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN/8;
+	slen = strlen((const char *)block->description);
+	pack_uint32_(slen, buffer, len);
+	if(write_cb(buffer, 1, len, handle) != len)
+		return false;
+	if(write_cb(block->description, 1, slen, handle) != slen)
+		return false;
+
+	len = FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN/8;
+	pack_uint32_(block->width, buffer, len);
+	if(write_cb(buffer, 1, len, handle) != len)
+		return false;
+
+	len = FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN/8;
+	pack_uint32_(block->height, buffer, len);
+	if(write_cb(buffer, 1, len, handle) != len)
+		return false;
+
+	len = FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN/8;
+	pack_uint32_(block->depth, buffer, len);
+	if(write_cb(buffer, 1, len, handle) != len)
+		return false;
+
+	len = FLAC__STREAM_METADATA_PICTURE_COLORS_LEN/8;
+	pack_uint32_(block->colors, buffer, len);
+	if(write_cb(buffer, 1, len, handle) != len)
+		return false;
+
+	len = FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN/8;
+	pack_uint32_(block->data_length, buffer, len);
+	if(write_cb(buffer, 1, len, handle) != len)
+		return false;
+	if(write_cb(block->data, 1, block->data_length, handle) != block->data_length)
+		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)
@@ -2434,7 +2851,7 @@
 
 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)) {
+	if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) {
 		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
 		return false;
 	}
@@ -2445,7 +2862,7 @@
 	if(!write_metadata_block_data_(iterator->file, &iterator->status, block))
 		return false;
 
-	if(0 != fseek(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) {
+	if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) {
 		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
 		return false;
 	}
@@ -2457,7 +2874,7 @@
 {
 	FLAC__StreamMetadata *padding;
 
-	if(0 != fseek(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) {
+	if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) {
 		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
 		return false;
 	}
@@ -2488,7 +2905,7 @@
 
 	FLAC__metadata_object_delete(padding);
 
-	if(0 != fseek(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) {
+	if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) {
 		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
 		return false;
 	}
@@ -2498,10 +2915,10 @@
 
 FLAC__bool rewrite_whole_file_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool append)
 {
-	FILE *tempfile;
-	char *tempfilename;
+	FILE *tempfile = NULL;
+	char *tempfilename = NULL;
 	int fixup_is_last_code = 0; /* 0 => no need to change any is_last flags */
-	long fixup_is_last_flag_offset = -1;
+	FLAC__off_t fixup_is_last_flag_offset = -1;
 
 	FLAC__ASSERT(0 != block || append == false);
 
@@ -2558,7 +2975,7 @@
 {
 	FLAC__ASSERT(iterator->depth > 0);
 	iterator->depth--;
-	if(0 != fseek(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) {
+	if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) {
 		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
 		return false;
 	}
@@ -2578,7 +2995,7 @@
 	size_t n;
 	unsigned i;
 
-	FLAC__ASSERT(FLAC__STREAM_SYNC_LENGTH == 4);
+	FLAC__ASSERT(FLAC__STREAM_SYNC_LENGTH == sizeof(buffer));
 
 	/* skip any id3v2 tag */
 	errno = 0;
@@ -2629,9 +3046,9 @@
 
 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];
+	const FLAC__off_t offset_end = append? iterator->offset[iterator->depth] + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH + (FLAC__off_t)iterator->length : iterator->offset[iterator->depth];
 
-	if(0 != fseek(iterator->file, 0, SEEK_SET)) {
+	if(0 != fseeko(iterator->file, 0, SEEK_SET)) {
 		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
 		return false;
 	}
@@ -2647,12 +3064,12 @@
 	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)
+FLAC__bool simple_iterator_copy_file_postfix_(FLAC__Metadata_SimpleIterator *iterator, FILE **tempfile, char **tempfilename, int fixup_is_last_code, FLAC__off_t fixup_is_last_flag_offset, FLAC__bool backup)
 {
-	long save_offset = iterator->offset[iterator->depth]; /*@@@ 2G limit */
+	FLAC__off_t save_offset = iterator->offset[iterator->depth];
 	FLAC__ASSERT(0 != *tempfile);
 
-	if(0 != fseek(iterator->file, save_offset + FLAC__STREAM_METADATA_HEADER_LENGTH + iterator->length, SEEK_SET)) {
+	if(0 != fseeko(iterator->file, save_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH + (FLAC__off_t)iterator->length, SEEK_SET)) {
 		cleanup_tempfile_(tempfile, tempfilename);
 		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
 		return false;
@@ -2671,7 +3088,7 @@
 		 */
 		/* 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)) {
+		if(0 != fseeko(*tempfile, fixup_is_last_flag_offset, SEEK_SET)) {
 			cleanup_tempfile_(tempfile, tempfilename);
 			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
 			return false;
@@ -2689,7 +3106,7 @@
 			FLAC__ASSERT(!(x & 0x80));
 			x |= 0x80;
 		}
-		if(0 != fseek(*tempfile, fixup_is_last_flag_offset, SEEK_SET)) {
+		if(0 != fseeko(*tempfile, fixup_is_last_flag_offset, SEEK_SET)) {
 			cleanup_tempfile_(tempfile, tempfilename);
 			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
 			return false;
@@ -2712,7 +3129,7 @@
 	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)
+		while(iterator->offset[iterator->depth] + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH + (FLAC__off_t)iterator->length < save_offset)
 			if(!FLAC__metadata_simple_iterator_next(iterator))
 				return false;
 		return true;
@@ -2726,13 +3143,14 @@
 	}
 }
 
-FLAC__bool copy_n_bytes_from_file_(FILE *file, FILE *tempfile, unsigned bytes/*@@@ 4G limit*/, FLAC__Metadata_SimpleIteratorStatus *status)
+FLAC__bool copy_n_bytes_from_file_(FILE *file, FILE *tempfile, FLAC__off_t bytes, FLAC__Metadata_SimpleIteratorStatus *status)
 {
 	FLAC__byte buffer[8192];
-	unsigned n;
+	size_t n;
 
+	FLAC__ASSERT(bytes >= 0);
 	while(bytes > 0) {
-		n = min(sizeof(buffer), bytes);
+		n = flac_min(sizeof(buffer), (size_t)bytes);
 		if(fread(buffer, 1, n, file) != n) {
 			*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
 			return false;
@@ -2747,13 +3165,14 @@
 	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__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, FLAC__off_t bytes, FLAC__Metadata_SimpleIteratorStatus *status)
 {
 	FLAC__byte buffer[8192];
-	unsigned n;
+	size_t n;
 
+	FLAC__ASSERT(bytes >= 0);
 	while(bytes > 0) {
-		n = min(sizeof(buffer), bytes);
+		n = flac_min(sizeof(buffer), (size_t)bytes);
 		if(read_cb(buffer, 1, n, handle) != n) {
 			*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
 			return false;
@@ -2808,35 +3227,59 @@
 	return true;
 }
 
+static int
+local_snprintf(char *str, size_t size, const char *fmt, ...)
+{
+	va_list va;
+	int rc;
+
+	va_start (va, fmt);
+
+#if defined _MSC_VER
+	if (size == 0)
+		return 1024;
+	rc = vsnprintf_s (str, size, _TRUNCATE, fmt, va);
+	if (rc < 0)
+		rc = size - 1;
+#elif defined __MINGW32__
+	rc = __mingw_vsnprintf (str, size, fmt, va);
+#else
+	rc = vsnprintf (str, size, fmt, va);
+#endif
+	va_end (va);
+
+	return rc;
+}
+
 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))) {
+		size_t dest_len = strlen(filename) + strlen(tempfile_suffix) + 1;
+		if(0 == (*tempfilename = safe_malloc_(dest_len))) {
 			*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
 			return false;
 		}
-		strcpy(*tempfilename, filename);
-		strcat(*tempfilename, tempfile_suffix);
+		local_snprintf(*tempfilename, dest_len, "%s%s", filename, tempfile_suffix);
 	}
 	else {
 		const char *p = strrchr(filename, '/');
+		size_t dest_len;
 		if(0 == p)
 			p = filename;
 		else
 			p++;
 
-		if(0 == (*tempfilename = (char*)malloc(strlen(tempfile_path_prefix) + 1 + strlen(p) + strlen(tempfile_suffix) + 1))) {
+		dest_len = strlen(tempfile_path_prefix) + strlen(p) + strlen(tempfile_suffix) + 2;
+
+		if(0 == (*tempfilename = safe_malloc_(dest_len))) {
 			*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);
+		local_snprintf(*tempfilename, dest_len, "%s/%s%s", tempfile_path_prefix, p, tempfile_suffix);
 	}
 
-	if(0 == (*tempfile = fopen(*tempfilename, "w+b"))) {
+	if(0 == (*tempfile = flac_fopen(*tempfilename, "w+b"))) {
 		*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE;
 		return false;
 	}
@@ -2856,8 +3299,9 @@
 	(void)fclose(*tempfile);
 	*tempfile = 0;
 
-#if defined _MSC_VER || defined __MINGW32__
-	if(unlink(filename) < 0) {
+#if defined _MSC_VER || defined __BORLANDC__ || defined __MINGW32__ || defined __EMX__
+	/* on some flavors of windows, flac_rename() will fail if the destination already exists */
+	if(flac_unlink(filename) < 0) {
 		cleanup_tempfile_(tempfile, tempfilename);
 		*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_UNLINK_ERROR;
 		return false;
@@ -2864,8 +3308,8 @@
 	}
 #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)) {
+	/*@@@ to fully support the tempfile_path_prefix we need to update this piece to actually copy across filesystems instead of just flac_rename(): */
+	if(0 != flac_rename(*tempfilename, filename)) {
 		cleanup_tempfile_(tempfile, tempfilename);
 		*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_RENAME_ERROR;
 		return false;
@@ -2884,20 +3328,20 @@
 	}
 
 	if(0 != *tempfilename) {
-		(void)unlink(*tempfilename);
+		(void)flac_unlink(*tempfilename);
 		free(*tempfilename);
 		*tempfilename = 0;
 	}
 }
 
-FLAC__bool get_file_stats_(const char *filename, struct stat *stats)
+FLAC__bool get_file_stats_(const char *filename, struct flac_stat_s *stats)
 {
 	FLAC__ASSERT(0 != filename);
 	FLAC__ASSERT(0 != stats);
-	return (0 == stat(filename, stats));
+	return (0 == flac_stat(filename, stats));
 }
 
-void set_file_stats_(const char *filename, struct stat *stats)
+void set_file_stats_(const char *filename, struct flac_stat_s *stats)
 {
 	struct utimbuf srctime;
 
@@ -2906,28 +3350,22 @@
 
 	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);
+	(void)flac_chmod(filename, stats->st_mode);
+	(void)flac_utime(filename, &srctime);
+#if !defined _MSC_VER && !defined __BORLANDC__ && !defined __MINGW32__
+	FLAC_CHECK_RETURN(chown(filename, stats->st_uid, -1));
+	FLAC_CHECK_RETURN(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);
+	return fseeko((FILE*)handle, (FLAC__off_t)offset, whence);
 }
 
 FLAC__int64 ftell_wrapper_(FLAC__IOHandle handle)
 {
-	return (long)ftell((FILE*)handle);
+	return ftello((FILE*)handle);
 }
 
 FLAC__Metadata_ChainStatus get_equivalent_status_(FLAC__Metadata_SimpleIteratorStatus status)
--- a/sys/src/cmd/audio/libFLAC/metadata_object.c
+++ b/sys/src/cmd/audio/libFLAC/metadata_object.c
@@ -1,5 +1,6 @@
 /* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2001,2002,2003,2004  Josh Coalson
+ * Copyright (C) 2001-2009  Josh Coalson
+ * Copyright (C) 2011-2014  Xiph.Org Foundation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -29,14 +30,24 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
 #include <stdlib.h>
 #include <string.h>
 
 #include "private/metadata.h"
+#include "private/memory.h"
 
 #include "FLAC/assert.h"
+#include "share/alloc.h"
+#include "share/compat.h"
 
+/* Alias the first (in share/alloc.h) to the second (in src/libFLAC/memory.c). */
+#define safe_malloc_mul_2op_ safe_malloc_mul_2op_p
 
+
 /****************************************************************************
  *
  * Local routines
@@ -43,11 +54,20 @@
  *
  ***************************************************************************/
 
+/* copy bytes:
+ *  from = NULL  && bytes = 0
+ *       to <- NULL
+ *  from != NULL && bytes > 0
+ *       to <- copy of from
+ *  else ASSERT
+ * malloc error leaves 'to' unchanged
+ */
 static FLAC__bool copy_bytes_(FLAC__byte **to, const FLAC__byte *from, unsigned bytes)
 {
+	FLAC__ASSERT(0 != to);
 	if(bytes > 0 && 0 != from) {
 		FLAC__byte *x;
-		if(0 == (x = (FLAC__byte*)malloc(bytes)))
+		if(0 == (x = safe_malloc_(bytes)))
 			return false;
 		memcpy(x, from, bytes);
 		*to = x;
@@ -60,6 +80,55 @@
 	return true;
 }
 
+#if 0 /* UNUSED */
+/* like copy_bytes_(), but free()s the original '*to' if the copy succeeds and the original '*to' is non-NULL */
+static FLAC__bool free_copy_bytes_(FLAC__byte **to, const FLAC__byte *from, unsigned bytes)
+{
+	FLAC__byte *copy;
+	FLAC__ASSERT(0 != to);
+	if(copy_bytes_(&copy, from, bytes)) {
+		if(*to)
+			free(*to);
+		*to = copy;
+		return true;
+	}
+	else
+		return false;
+}
+#endif
+
+/* reallocate entry to 1 byte larger and add a terminating NUL */
+/* realloc() failure leaves entry unchanged */
+static FLAC__bool ensure_null_terminated_(FLAC__byte **entry, unsigned length)
+{
+	FLAC__byte *x = safe_realloc_add_2op_(*entry, length, /*+*/1);
+	if(0 != x) {
+		x[length] = '\0';
+		*entry = x;
+		return true;
+	}
+	else
+		return false;
+}
+
+/* copies the NUL-terminated C-string 'from' to '*to', leaving '*to'
+ * unchanged if malloc fails, free()ing the original '*to' if it
+ * succeeds and the original '*to' was not NULL
+ */
+static FLAC__bool copy_cstring_(char **to, const char *from)
+{
+	char *copy = strdup(from);
+	FLAC__ASSERT(to);
+	if(copy) {
+		if(*to)
+			free(*to);
+		*to = copy;
+		return true;
+	}
+	else
+		return false;
+}
+
 static FLAC__bool copy_vcentry_(FLAC__StreamMetadata_VorbisComment_Entry *to, const FLAC__StreamMetadata_VorbisComment_Entry *from)
 {
 	to->length = from->length;
@@ -70,9 +139,10 @@
 	else {
 		FLAC__byte *x;
 		FLAC__ASSERT(from->length > 0);
-		if(0 == (x = (FLAC__byte*)malloc(from->length)))
+		if(0 == (x = safe_malloc_add_2op_(from->length, /*+*/1)))
 			return false;
 		memcpy(x, from->entry, from->length);
+		x[from->length] = '\0';
 		to->entry = x;
 	}
 	return true;
@@ -87,7 +157,7 @@
 	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))))
+		if(0 == (x = safe_malloc_mul_2op_p(from->num_indices, /*times*/sizeof(FLAC__StreamMetadata_CueSheet_Index))))
 			return false;
 		memcpy(x, from->indices, from->num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index));
 		to->indices = x;
@@ -109,7 +179,7 @@
 
 	FLAC__ASSERT(num_points > 0);
 
-	object_array = (FLAC__StreamMetadata_SeekPoint*)malloc(num_points * sizeof(FLAC__StreamMetadata_SeekPoint));
+	object_array = safe_malloc_mul_2op_p(num_points, /*times*/sizeof(FLAC__StreamMetadata_SeekPoint));
 
 	if(0 != object_array) {
 		unsigned i;
@@ -142,7 +212,7 @@
 {
 	FLAC__ASSERT(num_comments > 0);
 
-	return (FLAC__StreamMetadata_VorbisComment_Entry*)calloc(num_comments, sizeof(FLAC__StreamMetadata_VorbisComment_Entry));
+	return safe_calloc_(num_comments, sizeof(FLAC__StreamMetadata_VorbisComment_Entry));
 }
 
 static void vorbiscomment_entry_array_delete_(FLAC__StreamMetadata_VorbisComment_Entry *object_array, unsigned num_comments)
@@ -194,13 +264,30 @@
 
 	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;
+	if(0 != src->entry) {
+		if(copy) {
+			/* do the copy first so that if we fail we leave the dest object untouched */
+			if(!copy_vcentry_(dest, src))
+				return false;
+		}
+		else {
+			/* we have to make sure that the string we're taking over is null-terminated */
+
+			/*
+			 * Stripping the const from src->entry is OK since we're taking
+			 * ownership of the pointer.  This is a hack around a deficiency
+			 * in the API where the same function is used for 'copy' and
+			 * 'own', but the source entry is a const pointer.  If we were
+			 * precise, the 'own' flavor would be a separate function with a
+			 * non-const source pointer.  But it's not, so we hack away.
+			 */
+			if(!ensure_null_terminated_((FLAC__byte**)(&src->entry), src->length))
+				return false;
+			*dest = *src;
+		}
 	}
 	else {
-		/* either we're not copying or the src is null */
+		/* the src is null */
 		*dest = *src;
 	}
 
@@ -211,6 +298,22 @@
 	return true;
 }
 
+static int vorbiscomment_find_entry_from_(const FLAC__StreamMetadata *object, unsigned offset, const char *field_name, unsigned field_name_length)
+{
+	unsigned i;
+
+	FLAC__ASSERT(0 != object);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+	FLAC__ASSERT(0 != field_name);
+
+	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;
+}
+
 static void cuesheet_calculate_length_(FLAC__StreamMetadata *object)
 {
 	unsigned i;
@@ -248,7 +351,7 @@
 {
 	FLAC__ASSERT(num_indices > 0);
 
-	return (FLAC__StreamMetadata_CueSheet_Index*)calloc(num_indices, sizeof(FLAC__StreamMetadata_CueSheet_Index));
+	return safe_calloc_(num_indices, sizeof(FLAC__StreamMetadata_CueSheet_Index));
 }
 
 static FLAC__StreamMetadata_CueSheet_Track *cuesheet_track_array_new_(unsigned num_tracks)
@@ -255,7 +358,7 @@
 {
 	FLAC__ASSERT(num_tracks > 0);
 
-	return (FLAC__StreamMetadata_CueSheet_Track*)calloc(num_tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track));
+	return safe_calloc_(num_tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track));
 }
 
 static void cuesheet_track_array_delete_(FLAC__StreamMetadata_CueSheet_Track *object_array, unsigned num_tracks)
@@ -337,10 +440,10 @@
 {
 	FLAC__StreamMetadata *object;
 
-	if(type > FLAC__MAX_METADATA_TYPE_CODE)
+	if(type > FLAC__MAX_METADATA_TYPE)
 		return 0;
 
-	object = (FLAC__StreamMetadata*)calloc(1, sizeof(FLAC__StreamMetadata));
+	object = calloc(1, sizeof(FLAC__StreamMetadata));
 	if(0 != object) {
 		object->is_last = false;
 		object->type = type;
@@ -367,18 +470,51 @@
 				*/
 				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);
+				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+1)) {
+					free(object);
+					return 0;
 				}
+				vorbiscomment_calculate_length_(object);
 				break;
 			case FLAC__METADATA_TYPE_CUESHEET:
 				cuesheet_calculate_length_(object);
 				break;
+			case FLAC__METADATA_TYPE_PICTURE:
+				object->length = (
+					FLAC__STREAM_METADATA_PICTURE_TYPE_LEN +
+					FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN + /* empty mime_type string */
+					FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN + /* empty description string */
+					FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN +
+					FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN +
+					FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN +
+					FLAC__STREAM_METADATA_PICTURE_COLORS_LEN +
+					FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN +
+					0 /* no data */
+				) / 8;
+				object->data.picture.type = FLAC__STREAM_METADATA_PICTURE_TYPE_OTHER;
+				object->data.picture.mime_type = 0;
+				object->data.picture.description = 0;
+				/* calloc() took care of this for us:
+				object->data.picture.width = 0;
+				object->data.picture.height = 0;
+				object->data.picture.depth = 0;
+				object->data.picture.colors = 0;
+				object->data.picture.data_length = 0;
+				object->data.picture.data = 0;
+				*/
+				/* now initialize mime_type and description with empty strings to make things easier on the client */
+				if(!copy_cstring_(&object->data.picture.mime_type, "")) {
+					free(object);
+					return 0;
+				}
+				if(!copy_cstring_((char**)(&object->data.picture.description), "")) {
+					if(object->data.picture.mime_type)
+						free(object->data.picture.mime_type);
+					free(object);
+					return 0;
+				}
+				break;
 			default:
 				/* calloc() took care of this for us:
 				object->length = 0;
@@ -408,6 +544,10 @@
 			case FLAC__METADATA_TYPE_PADDING:
 				break;
 			case FLAC__METADATA_TYPE_APPLICATION:
+				if(to->length < FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8) { /* underflow check */
+					FLAC__metadata_object_delete(to);
+					return 0;
+				}
 				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);
@@ -416,6 +556,10 @@
 				break;
 			case FLAC__METADATA_TYPE_SEEKTABLE:
 				to->data.seek_table.num_points = object->data.seek_table.num_points;
+				if(to->data.seek_table.num_points > UINT32_MAX / sizeof(FLAC__StreamMetadata_SeekPoint)) { /* overflow check */
+					FLAC__metadata_object_delete(to);
+					return 0;
+				}
 				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;
@@ -458,6 +602,26 @@
 					}
 				}
 				break;
+			case FLAC__METADATA_TYPE_PICTURE:
+				to->data.picture.type = object->data.picture.type;
+				if(!copy_cstring_(&to->data.picture.mime_type, object->data.picture.mime_type)) {
+					FLAC__metadata_object_delete(to);
+					return 0;
+				}
+				if(!copy_cstring_((char**)(&to->data.picture.description), (const char*)object->data.picture.description)) {
+					FLAC__metadata_object_delete(to);
+					return 0;
+				}
+				to->data.picture.width = object->data.picture.width;
+				to->data.picture.height = object->data.picture.height;
+				to->data.picture.depth = object->data.picture.depth;
+				to->data.picture.colors = object->data.picture.colors;
+				to->data.picture.data_length = object->data.picture.data_length;
+				if(!copy_bytes_((&to->data.picture.data), object->data.picture.data, object->data.picture.data_length)) {
+					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);
@@ -506,6 +670,20 @@
 				cuesheet_track_array_delete_(object->data.cue_sheet.tracks, object->data.cue_sheet.num_tracks);
 			}
 			break;
+		case FLAC__METADATA_TYPE_PICTURE:
+			if(0 != object->data.picture.mime_type) {
+				free(object->data.picture.mime_type);
+				object->data.picture.mime_type = 0;
+			}
+			if(0 != object->data.picture.description) {
+				free(object->data.picture.description);
+				object->data.picture.description = 0;
+			}
+			if(0 != object->data.picture.data) {
+				free(object->data.picture.data);
+				object->data.picture.data = 0;
+			}
+			break;
 		default:
 			if(0 != object->data.unknown.data) {
 				free(object->data.unknown.data);
@@ -660,6 +838,29 @@
 	return true;
 }
 
+static FLAC__bool compare_block_data_picture_(const FLAC__StreamMetadata_Picture *block1, const FLAC__StreamMetadata_Picture *block2)
+{
+	if(block1->type != block2->type)
+		return false;
+	if(block1->mime_type != block2->mime_type && (0 == block1->mime_type || 0 == block2->mime_type || strcmp(block1->mime_type, block2->mime_type)))
+		return false;
+	if(block1->description != block2->description && (0 == block1->description || 0 == block2->description || strcmp((const char *)block1->description, (const char *)block2->description)))
+		return false;
+	if(block1->width != block2->width)
+		return false;
+	if(block1->height != block2->height)
+		return false;
+	if(block1->depth != block2->depth)
+		return false;
+	if(block1->colors != block2->colors)
+		return false;
+	if(block1->data_length != block2->data_length)
+		return false;
+	if(block1->data != block2->data && (0 == block1->data || 0 == block2->data || memcmp(block1->data, block2->data, block1->data_length)))
+		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);
@@ -698,6 +899,8 @@
 			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);
+		case FLAC__METADATA_TYPE_PICTURE:
+			return compare_block_data_picture_(&block1->data.picture, &block2->data.picture);
 		default:
 			return compare_block_data_unknown_(&block1->data.unknown, &block2->data.unknown, block1->length);
 	}
@@ -742,9 +945,13 @@
 			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);
+		const size_t old_size = object->data.seek_table.num_points * sizeof(FLAC__StreamMetadata_SeekPoint);
+		const size_t new_size = new_num_points * sizeof(FLAC__StreamMetadata_SeekPoint);
 
+		/* overflow check */
+		if(new_num_points > UINT32_MAX / sizeof(FLAC__StreamMetadata_SeekPoint))
+			return false;
+
 		FLAC__ASSERT(object->data.seek_table.num_points > 0);
 
 		if(new_size == 0) {
@@ -751,7 +958,7 @@
 			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)))
+		else if(0 == (object->data.seek_table.points = realloc(object->data.seek_table.points, new_size)))
 			return false;
 
 		/* if growing, set new elements to placeholders */
@@ -885,7 +1092,7 @@
 	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
 	FLAC__ASSERT(total_samples > 0);
 
-	if(num > 0) {
+	if(num > 0 && total_samples > 0) {
 		FLAC__StreamMetadata_SeekTable *seek_table = &object->data.seek_table;
 		unsigned i, j;
 
@@ -904,6 +1111,39 @@
 	return true;
 }
 
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(FLAC__StreamMetadata *object, unsigned samples, FLAC__uint64 total_samples)
+{
+	FLAC__ASSERT(0 != object);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
+	FLAC__ASSERT(samples > 0);
+	FLAC__ASSERT(total_samples > 0);
+
+	if(samples > 0 && total_samples > 0) {
+		FLAC__StreamMetadata_SeekTable *seek_table = &object->data.seek_table;
+		unsigned i, j;
+		FLAC__uint64 num, sample;
+
+		num = 1 + total_samples / samples; /* 1+ for the first sample at 0 */
+		/* now account for the fact that we don't place a seekpoint at "total_samples" since samples are number from 0: */
+		if(total_samples % samples == 0)
+			num--;
+
+		i = seek_table->num_points;
+
+		if(!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + (unsigned)num))
+			return false;
+
+		sample = 0;
+		for(j = 0; j < num; i++, j++, sample += samples) {
+			seek_table->points[i].sample_number = sample;
+			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;
@@ -918,6 +1158,8 @@
 
 FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_vendor_string(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy)
 {
+	if(!FLAC__format_vorbiscomment_entry_value_is_legal(entry.entry, entry.length))
+		return false;
 	return vorbiscomment_set_entry_(object, &object->data.vorbis_comment.vendor_string, &entry, copy);
 }
 
@@ -934,9 +1176,13 @@
 			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);
+		const size_t old_size = object->data.vorbis_comment.num_comments * sizeof(FLAC__StreamMetadata_VorbisComment_Entry);
+		const size_t new_size = new_num_comments * sizeof(FLAC__StreamMetadata_VorbisComment_Entry);
 
+		/* overflow check */
+		if(new_num_comments > UINT32_MAX / sizeof(FLAC__StreamMetadata_VorbisComment_Entry))
+			return false;
+
 		FLAC__ASSERT(object->data.vorbis_comment.num_comments > 0);
 
 		/* if shrinking, free the truncated entries */
@@ -951,7 +1197,7 @@
 			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)))
+		else if(0 == (object->data.vorbis_comment.comments = realloc(object->data.vorbis_comment.comments, new_size)))
 			return false;
 
 		/* if growing, zero all the length/pointers of new elements */
@@ -970,6 +1216,8 @@
 	FLAC__ASSERT(0 != object);
 	FLAC__ASSERT(comment_num < object->data.vorbis_comment.num_comments);
 
+	if(!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length))
+		return false;
 	return vorbiscomment_set_entry_(object, &object->data.vorbis_comment.comments[comment_num], &entry, copy);
 }
 
@@ -981,6 +1229,9 @@
 	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
 	FLAC__ASSERT(comment_num <= object->data.vorbis_comment.num_comments);
 
+	if(!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length))
+		return false;
+
 	vc = &object->data.vorbis_comment;
 
 	if(!FLAC__metadata_object_vorbiscomment_resize_comments(object, vc->num_comments+1))
@@ -994,6 +1245,58 @@
 	return FLAC__metadata_object_vorbiscomment_set_comment(object, comment_num, entry, copy);
 }
 
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_append_comment(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy)
+{
+	FLAC__ASSERT(0 != object);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+	return FLAC__metadata_object_vorbiscomment_insert_comment(object, object->data.vorbis_comment.num_comments, entry, copy);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_replace_comment(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool all, FLAC__bool copy)
+{
+	FLAC__ASSERT(0 != entry.entry && entry.length > 0);
+
+	if(!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length))
+		return false;
+
+	{
+		int i;
+		size_t field_name_length;
+		const FLAC__byte *eq = (FLAC__byte*)memchr(entry.entry, '=', entry.length);
+
+		FLAC__ASSERT(0 != eq);
+
+		if(0 == eq)
+			return false; /* double protection */
+
+		field_name_length = eq-entry.entry;
+
+		i = vorbiscomment_find_entry_from_(object, 0, (const char *)entry.entry, field_name_length);
+		if(i >= 0) {
+			unsigned indx = (unsigned)i;
+			if(!FLAC__metadata_object_vorbiscomment_set_comment(object, indx, entry, copy))
+				return false;
+			entry = object->data.vorbis_comment.comments[indx];
+			indx++; /* skip over replaced comment */
+			if(all && indx < object->data.vorbis_comment.num_comments) {
+				i = vorbiscomment_find_entry_from_(object, indx, (const char *)entry.entry, field_name_length);
+				while(i >= 0) {
+					indx = (unsigned)i;
+					if(!FLAC__metadata_object_vorbiscomment_delete_comment(object, indx))
+						return false;
+					if(indx < object->data.vorbis_comment.num_comments)
+						i = vorbiscomment_find_entry_from_(object, indx, (const char *)entry.entry, field_name_length);
+					else
+						i = -1;
+				}
+			}
+			return true;
+		}
+		else
+			return FLAC__metadata_object_vorbiscomment_append_comment(object, entry, copy);
+	}
+}
+
 FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_delete_comment(FLAC__StreamMetadata *object, unsigned comment_num)
 {
 	FLAC__StreamMetadata_VorbisComment *vc;
@@ -1016,34 +1319,79 @@
 	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)
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(FLAC__StreamMetadata_VorbisComment_Entry *entry, const char *field_name, const char *field_value)
 {
-	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__ASSERT(0 != entry);
+	FLAC__ASSERT(0 != field_name);
+	FLAC__ASSERT(0 != field_value);
+
+	if(!FLAC__format_vorbiscomment_entry_name_is_legal(field_name))
+		return false;
+	if(!FLAC__format_vorbiscomment_entry_value_is_legal((const FLAC__byte *)field_value, (unsigned)(-1)))
+		return false;
+
+	{
+		const size_t nn = strlen(field_name);
+		const size_t nv = strlen(field_value);
+		entry->length = nn + 1 /*=*/ + nv;
+		if(0 == (entry->entry = safe_malloc_add_4op_(nn, /*+*/1, /*+*/nv, /*+*/1)))
+			return false;
+		memcpy(entry->entry, field_name, nn);
+		entry->entry[nn] = '=';
+		memcpy(entry->entry+nn+1, field_value, nv);
+		entry->entry[entry->length] = '\0';
+	}
+
+	return true;
 }
 
-FLAC_API int FLAC__metadata_object_vorbiscomment_find_entry_from(const FLAC__StreamMetadata *object, unsigned offset, const char *field_name)
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_to_name_value_pair(const FLAC__StreamMetadata_VorbisComment_Entry entry, char **field_name, char **field_value)
 {
-	const unsigned field_name_length = strlen(field_name);
-	unsigned i;
+	FLAC__ASSERT(0 != entry.entry && entry.length > 0);
+	FLAC__ASSERT(0 != field_name);
+	FLAC__ASSERT(0 != field_value);
 
-	FLAC__ASSERT(0 != object);
-	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+	if(!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length))
+		return false;
 
-	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;
+	{
+		const FLAC__byte *eq = (FLAC__byte*)memchr(entry.entry, '=', entry.length);
+		const size_t nn = eq-entry.entry;
+		const size_t nv = entry.length-nn-1; /* -1 for the '=' */
+		FLAC__ASSERT(0 != eq);
+		if(0 == eq)
+			return false; /* double protection */
+		if(0 == (*field_name = safe_malloc_add_2op_(nn, /*+*/1)))
+			return false;
+		if(0 == (*field_value = safe_malloc_add_2op_(nv, /*+*/1))) {
+			free(*field_name);
+			return false;
+		}
+		memcpy(*field_name, entry.entry, nn);
+		memcpy(*field_value, entry.entry+nn+1, nv);
+		(*field_name)[nn] = '\0';
+		(*field_value)[nv] = '\0';
 	}
 
-	return -1;
+	return true;
 }
 
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_matches(const FLAC__StreamMetadata_VorbisComment_Entry entry, const char *field_name, unsigned field_name_length)
+{
+	FLAC__ASSERT(0 != entry.entry && entry.length > 0);
+	{
+		const FLAC__byte *eq = (FLAC__byte*)memchr(entry.entry, '=', entry.length);
+		return (0 != eq && (unsigned)(eq-entry.entry) == field_name_length && 0 == FLAC__STRNCASECMP(field_name, (const char *)entry.entry, field_name_length));
+	}
+}
+
+FLAC_API int FLAC__metadata_object_vorbiscomment_find_entry_from(const FLAC__StreamMetadata *object, unsigned offset, const char *field_name)
+{
+	FLAC__ASSERT(0 != field_name);
+
+	return vorbiscomment_find_entry_from_(object, offset, field_name, strlen(field_name));
+}
+
 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);
@@ -1053,7 +1401,7 @@
 	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_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
@@ -1076,7 +1424,7 @@
 
 	/* 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)) {
+		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);
 		}
@@ -1087,7 +1435,7 @@
 
 FLAC_API FLAC__StreamMetadata_CueSheet_Track *FLAC__metadata_object_cuesheet_track_new(void)
 {
-	return (FLAC__StreamMetadata_CueSheet_Track*)calloc(1, sizeof(FLAC__StreamMetadata_CueSheet_Track));
+	return 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)
@@ -1139,9 +1487,13 @@
 			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);
+		const size_t old_size = track->num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index);
+		const size_t new_size = new_num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index);
 
+		/* overflow check */
+		if(new_num_indices > UINT32_MAX / sizeof(FLAC__StreamMetadata_CueSheet_Index))
+			return false;
+
 		FLAC__ASSERT(track->num_indices > 0);
 
 		if(new_size == 0) {
@@ -1148,7 +1500,7 @@
 			free(track->indices);
 			track->indices = 0;
 		}
-		else if(0 == (track->indices = (FLAC__StreamMetadata_CueSheet_Index*)realloc(track->indices, new_size)))
+		else if(0 == (track->indices = realloc(track->indices, new_size)))
 			return false;
 
 		/* if growing, zero all the lengths/pointers of new elements */
@@ -1162,7 +1514,7 @@
 	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_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_index(FLAC__StreamMetadata *object, unsigned track_num, unsigned index_num, FLAC__StreamMetadata_CueSheet_Index indx)
 {
 	FLAC__StreamMetadata_CueSheet_Track *track;
 
@@ -1179,7 +1531,7 @@
 	/* 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;
+	track->indices[index_num] = indx;
 	cuesheet_calculate_length_(object);
 	return true;
 }
@@ -1186,9 +1538,9 @@
 
 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__StreamMetadata_CueSheet_Index indx;
+	memset(&indx, 0, sizeof(indx));
+	return FLAC__metadata_object_cuesheet_track_insert_index(object, track_num, index_num, indx);
 }
 
 FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_delete_index(FLAC__StreamMetadata *object, unsigned track_num, unsigned index_num)
@@ -1223,9 +1575,13 @@
 			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);
+		const size_t old_size = object->data.cue_sheet.num_tracks * sizeof(FLAC__StreamMetadata_CueSheet_Track);
+		const size_t new_size = new_num_tracks * sizeof(FLAC__StreamMetadata_CueSheet_Track);
 
+		/* overflow check */
+		if(new_num_tracks > UINT32_MAX / sizeof(FLAC__StreamMetadata_CueSheet_Track))
+			return false;
+
 		FLAC__ASSERT(object->data.cue_sheet.num_tracks > 0);
 
 		/* if shrinking, free the truncated entries */
@@ -1240,7 +1596,7 @@
 			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)))
+		else if(0 == (object->data.cue_sheet.tracks = realloc(object->data.cue_sheet.tracks, new_size)))
 			return false;
 
 		/* if growing, zero all the lengths/pointers of new elements */
@@ -1318,4 +1674,151 @@
 	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
 
 	return FLAC__format_cuesheet_is_legal(&object->data.cue_sheet, check_cd_da_subset, violation);
+}
+
+static FLAC__uint64 get_index_01_offset_(const FLAC__StreamMetadata_CueSheet *cs, unsigned track)
+{
+	if (track >= (cs->num_tracks-1) || cs->tracks[track].num_indices < 1)
+		return 0;
+	else if (cs->tracks[track].indices[0].number == 1)
+		return cs->tracks[track].indices[0].offset + cs->tracks[track].offset + cs->lead_in;
+	else if (cs->tracks[track].num_indices < 2)
+		return 0;
+	else if (cs->tracks[track].indices[1].number == 1)
+		return cs->tracks[track].indices[1].offset + cs->tracks[track].offset + cs->lead_in;
+	else
+		return 0;
+}
+
+static FLAC__uint32 cddb_add_digits_(FLAC__uint32 x)
+{
+	FLAC__uint32 n = 0;
+	while (x) {
+		n += (x%10);
+		x /= 10;
+	}
+	return n;
+}
+
+/*@@@@add to tests*/
+FLAC_API FLAC__uint32 FLAC__metadata_object_cuesheet_calculate_cddb_id(const FLAC__StreamMetadata *object)
+{
+	const FLAC__StreamMetadata_CueSheet *cs;
+
+	FLAC__ASSERT(0 != object);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
+
+	cs = &object->data.cue_sheet;
+
+	if (cs->num_tracks < 2) /* need at least one real track and the lead-out track */
+		return 0;
+
+	{
+		FLAC__uint32 i, length, sum = 0;
+		for (i = 0; i < (cs->num_tracks-1); i++) /* -1 to avoid counting the lead-out */
+			sum += cddb_add_digits_((FLAC__uint32)(get_index_01_offset_(cs, i) / 44100));
+		length = (FLAC__uint32)((cs->tracks[cs->num_tracks-1].offset+cs->lead_in) / 44100) - (FLAC__uint32)(get_index_01_offset_(cs, 0) / 44100);
+
+		return (sum % 0xFF) << 24 | length << 8 | (FLAC__uint32)(cs->num_tracks-1);
+	}
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_picture_set_mime_type(FLAC__StreamMetadata *object, char *mime_type, FLAC__bool copy)
+{
+	char *old;
+	size_t old_length, new_length;
+
+	FLAC__ASSERT(0 != object);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE);
+	FLAC__ASSERT(0 != mime_type);
+
+	old = object->data.picture.mime_type;
+	old_length = old? strlen(old) : 0;
+	new_length = strlen(mime_type);
+
+	/* do the copy first so that if we fail we leave the object untouched */
+	if(copy) {
+		if(new_length >= SIZE_MAX) /* overflow check */
+			return false;
+		if(!copy_bytes_((FLAC__byte**)(&object->data.picture.mime_type), (FLAC__byte*)mime_type, new_length+1))
+			return false;
+	}
+	else {
+		object->data.picture.mime_type = mime_type;
+	}
+
+	if(0 != old)
+		free(old);
+
+	object->length -= old_length;
+	object->length += new_length;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_picture_set_description(FLAC__StreamMetadata *object, FLAC__byte *description, FLAC__bool copy)
+{
+	FLAC__byte *old;
+	size_t old_length, new_length;
+
+	FLAC__ASSERT(0 != object);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE);
+	FLAC__ASSERT(0 != description);
+
+	old = object->data.picture.description;
+	old_length = old? strlen((const char *)old) : 0;
+	new_length = strlen((const char *)description);
+
+	/* do the copy first so that if we fail we leave the object untouched */
+	if(copy) {
+		if(new_length >= SIZE_MAX) /* overflow check */
+			return false;
+		if(!copy_bytes_(&object->data.picture.description, description, new_length+1))
+			return false;
+	}
+	else {
+		object->data.picture.description = description;
+	}
+
+	if(0 != old)
+		free(old);
+
+	object->length -= old_length;
+	object->length += new_length;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_picture_set_data(FLAC__StreamMetadata *object, FLAC__byte *data, FLAC__uint32 length, FLAC__bool copy)
+{
+	FLAC__byte *old;
+
+	FLAC__ASSERT(0 != object);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE);
+	FLAC__ASSERT((0 != data && length > 0) || (0 == data && length == 0 && copy == false));
+
+	old = object->data.picture.data;
+
+	/* do the copy first so that if we fail we leave the object untouched */
+	if(copy) {
+		if(!copy_bytes_(&object->data.picture.data, data, length))
+			return false;
+	}
+	else {
+		object->data.picture.data = data;
+	}
+
+	if(0 != old)
+		free(old);
+
+	object->length -= object->data.picture.data_length;
+	object->data.picture.data_length = length;
+	object->length += length;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_picture_is_legal(const FLAC__StreamMetadata *object, const char **violation)
+{
+	FLAC__ASSERT(0 != object);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE);
+
+	return FLAC__format_picture_is_legal(&object->data.picture, violation);
 }
--- a/sys/src/cmd/audio/libFLAC/mkfile
+++ b/sys/src/cmd/audio/libFLAC/mkfile
@@ -3,11 +3,13 @@
 LIB=libFLAC.a$O
 
 OFILES=\
-	bitbuffer.$O\
 	bitmath.$O\
+	bitreader.$O\
+	bitwriter.$O\
 	cpu.$O\
 	crc.$O\
 	fixed.$O\
+	float.$O\
 	format.$O\
 	lpc.$O\
 	md5.$O\
@@ -14,15 +16,16 @@
 	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\
+	ogg_decoder_aspect.$O\
+	ogg_encoder_aspect.$O\
+	ogg_helper.$O\
+	ogg_mapping.$O\
 	stream_decoder.$O\
+	stream_encoder.$O\
 	stream_encoder_framing.$O\
+	window.$O\
 
 CC=pcc
-CFLAGS=-I. -DVERSION="1.1.1" -DPlan9 -DFLAC__NO_NASM -DFLAC__ALIGN_MALLOC_DATA -D_BSD_EXTENSION -D_POSIX_SOURCE -c
+CFLAGS=-I. -I../libogg -DVERSION="1.3.1" -DPlan9 -DFLAC__HAS_OGG -DFLAC__ALIGN_MALLOC_DATA -D_C99_SNPRINTF_EXTENSION -D_BSD_EXTENSION -D_POSIX_SOURCE -c
 
 </sys/src/cmd/mklib
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/ogg_decoder_aspect.c
@@ -1,0 +1,251 @@
+/* libFLAC - Free Lossless Audio Codec
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2014  Xiph.Org Foundation
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <string.h> /* for memcpy() */
+#include "FLAC/assert.h"
+#include "private/ogg_decoder_aspect.h"
+#include "private/ogg_mapping.h"
+#include "private/macros.h"
+
+
+/***********************************************************************
+ *
+ * Public class methods
+ *
+ ***********************************************************************/
+
+FLAC__bool FLAC__ogg_decoder_aspect_init(FLAC__OggDecoderAspect *aspect)
+{
+	/* we will determine the serial number later if necessary */
+	if(ogg_stream_init(&aspect->stream_state, aspect->serial_number) != 0)
+		return false;
+
+	if(ogg_sync_init(&aspect->sync_state) != 0)
+		return false;
+
+	aspect->version_major = ~(0u);
+	aspect->version_minor = ~(0u);
+
+	aspect->need_serial_number = aspect->use_first_serial_number;
+
+	aspect->end_of_stream = false;
+	aspect->have_working_page = false;
+
+	return true;
+}
+
+void FLAC__ogg_decoder_aspect_finish(FLAC__OggDecoderAspect *aspect)
+{
+	(void)ogg_sync_clear(&aspect->sync_state);
+	(void)ogg_stream_clear(&aspect->stream_state);
+}
+
+void FLAC__ogg_decoder_aspect_set_serial_number(FLAC__OggDecoderAspect *aspect, long value)
+{
+	aspect->use_first_serial_number = false;
+	aspect->serial_number = value;
+}
+
+void FLAC__ogg_decoder_aspect_set_defaults(FLAC__OggDecoderAspect *aspect)
+{
+	aspect->use_first_serial_number = true;
+}
+
+void FLAC__ogg_decoder_aspect_flush(FLAC__OggDecoderAspect *aspect)
+{
+	(void)ogg_stream_reset(&aspect->stream_state);
+	(void)ogg_sync_reset(&aspect->sync_state);
+	aspect->end_of_stream = false;
+	aspect->have_working_page = false;
+}
+
+void FLAC__ogg_decoder_aspect_reset(FLAC__OggDecoderAspect *aspect)
+{
+	FLAC__ogg_decoder_aspect_flush(aspect);
+
+	if(aspect->use_first_serial_number)
+		aspect->need_serial_number = true;
+}
+
+FLAC__OggDecoderAspectReadStatus FLAC__ogg_decoder_aspect_read_callback_wrapper(FLAC__OggDecoderAspect *aspect, FLAC__byte buffer[], size_t *bytes, FLAC__OggDecoderAspectReadCallbackProxy read_callback, const FLAC__StreamDecoder *decoder, void *client_data)
+{
+	static const size_t OGG_BYTES_CHUNK = 8192;
+	const size_t bytes_requested = *bytes;
+
+	/*
+	 * The FLAC decoding API uses pull-based reads, whereas Ogg decoding
+	 * is push-based.  In libFLAC, when you ask to decode a frame, the
+	 * decoder will eventually call the read callback to supply some data,
+	 * but how much it asks for depends on how much free space it has in
+	 * its internal buffer.  It does not try to grow its internal buffer
+	 * to accomodate a whole frame because then the internal buffer size
+	 * could not be limited, which is necessary in embedded applications.
+	 *
+	 * Ogg however grows its internal buffer until a whole page is present;
+	 * only then can you get decoded data out.  So we can't just ask for
+	 * the same number of bytes from Ogg, then pass what's decoded down to
+	 * libFLAC.  If what libFLAC is asking for will not contain a whole
+	 * page, then we will get no data from ogg_sync_pageout(), and at the
+	 * same time cannot just read more data from the client for the purpose
+	 * of getting a whole decoded page because the decoded size might be
+	 * larger than libFLAC's internal buffer.
+	 *
+	 * Instead, whenever this read callback wrapper is called, we will
+	 * continually request data from the client until we have at least one
+	 * page, and manage pages internally so that we can send pieces of
+	 * pages down to libFLAC in such a way that we obey its size
+	 * requirement.  To limit the amount of callbacks, we will always try
+	 * to read in enough pages to return the full number of bytes
+	 * requested.
+	 */
+	*bytes = 0;
+	while (*bytes < bytes_requested && !aspect->end_of_stream) {
+		if (aspect->have_working_page) {
+			if (aspect->have_working_packet) {
+				size_t n = bytes_requested - *bytes;
+				if ((size_t)aspect->working_packet.bytes <= n) {
+					/* the rest of the packet will fit in the buffer */
+					n = aspect->working_packet.bytes;
+					memcpy(buffer, aspect->working_packet.packet, n);
+					*bytes += n;
+					buffer += n;
+					aspect->have_working_packet = false;
+				}
+				else {
+					/* only n bytes of the packet will fit in the buffer */
+					memcpy(buffer, aspect->working_packet.packet, n);
+					*bytes += n;
+					buffer += n;
+					aspect->working_packet.packet += n;
+					aspect->working_packet.bytes -= n;
+				}
+			}
+			else {
+				/* try and get another packet */
+				const int ret = ogg_stream_packetout(&aspect->stream_state, &aspect->working_packet);
+				if (ret > 0) {
+					aspect->have_working_packet = true;
+					/* if it is the first header packet, check for magic and a supported Ogg FLAC mapping version */
+					if (aspect->working_packet.bytes > 0 && aspect->working_packet.packet[0] == FLAC__OGG_MAPPING_FIRST_HEADER_PACKET_TYPE) {
+						const FLAC__byte *b = aspect->working_packet.packet;
+						const unsigned header_length =
+							FLAC__OGG_MAPPING_PACKET_TYPE_LENGTH +
+							FLAC__OGG_MAPPING_MAGIC_LENGTH +
+							FLAC__OGG_MAPPING_VERSION_MAJOR_LENGTH +
+							FLAC__OGG_MAPPING_VERSION_MINOR_LENGTH +
+							FLAC__OGG_MAPPING_NUM_HEADERS_LENGTH;
+						if (aspect->working_packet.bytes < (long)header_length)
+							return FLAC__OGG_DECODER_ASPECT_READ_STATUS_NOT_FLAC;
+						b += FLAC__OGG_MAPPING_PACKET_TYPE_LENGTH;
+						if (memcmp(b, FLAC__OGG_MAPPING_MAGIC, FLAC__OGG_MAPPING_MAGIC_LENGTH))
+							return FLAC__OGG_DECODER_ASPECT_READ_STATUS_NOT_FLAC;
+						b += FLAC__OGG_MAPPING_MAGIC_LENGTH;
+						aspect->version_major = (unsigned)(*b);
+						b += FLAC__OGG_MAPPING_VERSION_MAJOR_LENGTH;
+						aspect->version_minor = (unsigned)(*b);
+						if (aspect->version_major != 1)
+							return FLAC__OGG_DECODER_ASPECT_READ_STATUS_UNSUPPORTED_MAPPING_VERSION;
+						aspect->working_packet.packet += header_length;
+						aspect->working_packet.bytes -= header_length;
+					}
+				}
+				else if (ret == 0) {
+					aspect->have_working_page = false;
+				}
+				else { /* ret < 0 */
+					/* lost sync, we'll leave the working page for the next call */
+					return FLAC__OGG_DECODER_ASPECT_READ_STATUS_LOST_SYNC;
+				}
+			}
+		}
+		else {
+			/* try and get another page */
+			const int ret = ogg_sync_pageout(&aspect->sync_state, &aspect->working_page);
+			if (ret > 0) {
+				/* got a page, grab the serial number if necessary */
+				if(aspect->need_serial_number) {
+					aspect->stream_state.serialno = aspect->serial_number = ogg_page_serialno(&aspect->working_page);
+					aspect->need_serial_number = false;
+				}
+				if(ogg_stream_pagein(&aspect->stream_state, &aspect->working_page) == 0) {
+					aspect->have_working_page = true;
+					aspect->have_working_packet = false;
+				}
+				/* else do nothing, could be a page from another stream */
+			}
+			else if (ret == 0) {
+				/* need more data */
+				const size_t ogg_bytes_to_read = flac_max(bytes_requested - *bytes, OGG_BYTES_CHUNK);
+				char *oggbuf = ogg_sync_buffer(&aspect->sync_state, ogg_bytes_to_read);
+
+				if(0 == oggbuf) {
+					return FLAC__OGG_DECODER_ASPECT_READ_STATUS_MEMORY_ALLOCATION_ERROR;
+				}
+				else {
+					size_t ogg_bytes_read = ogg_bytes_to_read;
+
+					switch(read_callback(decoder, (FLAC__byte*)oggbuf, &ogg_bytes_read, client_data)) {
+						case FLAC__OGG_DECODER_ASPECT_READ_STATUS_OK:
+							break;
+						case FLAC__OGG_DECODER_ASPECT_READ_STATUS_END_OF_STREAM:
+							aspect->end_of_stream = true;
+							break;
+						case FLAC__OGG_DECODER_ASPECT_READ_STATUS_ABORT:
+							return FLAC__OGG_DECODER_ASPECT_READ_STATUS_ABORT;
+						default:
+							FLAC__ASSERT(0);
+					}
+
+					if(ogg_sync_wrote(&aspect->sync_state, ogg_bytes_read) < 0) {
+						/* double protection; this will happen if the read callback returns more bytes than the max requested, which would overflow Ogg's internal buffer */
+						FLAC__ASSERT(0);
+						return FLAC__OGG_DECODER_ASPECT_READ_STATUS_ERROR;
+					}
+				}
+			}
+			else { /* ret < 0 */
+				/* lost sync, bail out */
+				return FLAC__OGG_DECODER_ASPECT_READ_STATUS_LOST_SYNC;
+			}
+		}
+	}
+
+	if (aspect->end_of_stream && *bytes == 0) {
+		return FLAC__OGG_DECODER_ASPECT_READ_STATUS_END_OF_STREAM;
+	}
+
+	return FLAC__OGG_DECODER_ASPECT_READ_STATUS_OK;
+}
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/ogg_encoder_aspect.c
@@ -1,0 +1,228 @@
+/* libFLAC - Free Lossless Audio Codec
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2014  Xiph.Org Foundation
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <string.h> /* for memset() */
+#include "FLAC/assert.h"
+#include "private/ogg_encoder_aspect.h"
+#include "private/ogg_mapping.h"
+
+static const FLAC__byte FLAC__OGG_MAPPING_VERSION_MAJOR = 1;
+static const FLAC__byte FLAC__OGG_MAPPING_VERSION_MINOR = 0;
+
+/***********************************************************************
+ *
+ * Public class methods
+ *
+ ***********************************************************************/
+
+FLAC__bool FLAC__ogg_encoder_aspect_init(FLAC__OggEncoderAspect *aspect)
+{
+	/* we will determine the serial number later if necessary */
+	if(ogg_stream_init(&aspect->stream_state, aspect->serial_number) != 0)
+		return false;
+
+	aspect->seen_magic = false;
+	aspect->is_first_packet = true;
+	aspect->samples_written = 0;
+
+	return true;
+}
+
+void FLAC__ogg_encoder_aspect_finish(FLAC__OggEncoderAspect *aspect)
+{
+	(void)ogg_stream_clear(&aspect->stream_state);
+	/*@@@ what about the page? */
+}
+
+void FLAC__ogg_encoder_aspect_set_serial_number(FLAC__OggEncoderAspect *aspect, long value)
+{
+	aspect->serial_number = value;
+}
+
+FLAC__bool FLAC__ogg_encoder_aspect_set_num_metadata(FLAC__OggEncoderAspect *aspect, unsigned value)
+{
+	if(value < (1u << FLAC__OGG_MAPPING_NUM_HEADERS_LEN)) {
+		aspect->num_metadata = value;
+		return true;
+	}
+	else
+		return false;
+}
+
+void FLAC__ogg_encoder_aspect_set_defaults(FLAC__OggEncoderAspect *aspect)
+{
+	aspect->serial_number = 0;
+	aspect->num_metadata = 0;
+}
+
+/*
+ * The basic FLAC -> Ogg mapping goes like this:
+ *
+ * - 'fLaC' magic and STREAMINFO block get combined into the first
+ *   packet.  The packet is prefixed with
+ *   + the one-byte packet type 0x7F
+ *   + 'FLAC' magic
+ *   + the 2 byte Ogg FLAC mapping version number
+ *   + tne 2 byte big-endian # of header packets
+ * - The first packet is flushed to the first page.
+ * - Each subsequent metadata block goes into its own packet.
+ * - Each metadata packet is flushed to page (this is not required,
+ *   the mapping only requires that a flush must occur after all
+ *   metadata is written).
+ * - Each subsequent FLAC audio frame goes into its own packet.
+ *
+ * WATCHOUT:
+ * This depends on the behavior of FLAC__StreamEncoder that we get a
+ * separate write callback for the fLaC magic, and then separate write
+ * callbacks for each metadata block and audio frame.
+ */
+FLAC__StreamEncoderWriteStatus FLAC__ogg_encoder_aspect_write_callback_wrapper(FLAC__OggEncoderAspect *aspect, const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame, FLAC__bool is_last_block, FLAC__OggEncoderAspectWriteCallbackProxy write_callback, void *encoder, void *client_data)
+{
+	/* WATCHOUT:
+	 * This depends on the behavior of FLAC__StreamEncoder that 'samples'
+	 * will be 0 for metadata writes.
+	 */
+	const FLAC__bool is_metadata = (samples == 0);
+
+	/*
+	 * Treat fLaC magic packet specially.  We will note when we see it, then
+	 * wait until we get the STREAMINFO and prepend it in that packet
+	 */
+	if(aspect->seen_magic) {
+		ogg_packet packet;
+		FLAC__byte synthetic_first_packet_body[
+			FLAC__OGG_MAPPING_PACKET_TYPE_LENGTH +
+			FLAC__OGG_MAPPING_MAGIC_LENGTH +
+			FLAC__OGG_MAPPING_VERSION_MAJOR_LENGTH +
+			FLAC__OGG_MAPPING_VERSION_MINOR_LENGTH +
+			FLAC__OGG_MAPPING_NUM_HEADERS_LENGTH +
+			FLAC__STREAM_SYNC_LENGTH +
+			FLAC__STREAM_METADATA_HEADER_LENGTH +
+			FLAC__STREAM_METADATA_STREAMINFO_LENGTH
+		];
+
+		memset(&packet, 0, sizeof(packet));
+		packet.granulepos = aspect->samples_written + samples;
+
+		if(aspect->is_first_packet) {
+			FLAC__byte *b = synthetic_first_packet_body;
+			if(bytes != FLAC__STREAM_METADATA_HEADER_LENGTH + FLAC__STREAM_METADATA_STREAMINFO_LENGTH) {
+				/*
+				 * If we get here, our assumption about the way write callbacks happen
+				 * (explained above) is wrong
+				 */
+				FLAC__ASSERT(0);
+				return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
+			}
+			/* add first header packet type */
+			*b = FLAC__OGG_MAPPING_FIRST_HEADER_PACKET_TYPE;
+			b += FLAC__OGG_MAPPING_PACKET_TYPE_LENGTH;
+			/* add 'FLAC' mapping magic */
+			memcpy(b, FLAC__OGG_MAPPING_MAGIC, FLAC__OGG_MAPPING_MAGIC_LENGTH);
+			b += FLAC__OGG_MAPPING_MAGIC_LENGTH;
+			/* add Ogg FLAC mapping major version number */
+			memcpy(b, &FLAC__OGG_MAPPING_VERSION_MAJOR, FLAC__OGG_MAPPING_VERSION_MAJOR_LENGTH);
+			b += FLAC__OGG_MAPPING_VERSION_MAJOR_LENGTH;
+			/* add Ogg FLAC mapping minor version number */
+			memcpy(b, &FLAC__OGG_MAPPING_VERSION_MINOR, FLAC__OGG_MAPPING_VERSION_MINOR_LENGTH);
+			b += FLAC__OGG_MAPPING_VERSION_MINOR_LENGTH;
+			/* add number of header packets */
+			*b = (FLAC__byte)(aspect->num_metadata >> 8);
+			b++;
+			*b = (FLAC__byte)(aspect->num_metadata);
+			b++;
+			/* add native FLAC 'fLaC' magic */
+			memcpy(b, FLAC__STREAM_SYNC_STRING, FLAC__STREAM_SYNC_LENGTH);
+			b += FLAC__STREAM_SYNC_LENGTH;
+			/* add STREAMINFO */
+			memcpy(b, buffer, bytes);
+			FLAC__ASSERT(b + bytes - synthetic_first_packet_body == sizeof(synthetic_first_packet_body));
+			packet.packet = (unsigned char *)synthetic_first_packet_body;
+			packet.bytes = sizeof(synthetic_first_packet_body);
+
+			packet.b_o_s = 1;
+			aspect->is_first_packet = false;
+		}
+		else {
+			packet.packet = (unsigned char *)buffer;
+			packet.bytes = bytes;
+		}
+
+		if(is_last_block) {
+			/* we used to check:
+			 * FLAC__ASSERT(total_samples_estimate == 0 || total_samples_estimate == aspect->samples_written + samples);
+			 * but it's really not useful since total_samples_estimate is an estimate and can be inexact
+			 */
+			packet.e_o_s = 1;
+		}
+
+		if(ogg_stream_packetin(&aspect->stream_state, &packet) != 0)
+			return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
+
+		/*@@@ can't figure out a way to pass a useful number for 'samples' to the write_callback, so we'll just pass 0 */
+		if(is_metadata) {
+			while(ogg_stream_flush(&aspect->stream_state, &aspect->page) != 0) {
+				if(write_callback(encoder, aspect->page.header, aspect->page.header_len, 0, current_frame, client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK)
+					return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
+				if(write_callback(encoder, aspect->page.body, aspect->page.body_len, 0, current_frame, client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK)
+					return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
+			}
+		}
+		else {
+			while(ogg_stream_pageout(&aspect->stream_state, &aspect->page) != 0) {
+				if(write_callback(encoder, aspect->page.header, aspect->page.header_len, 0, current_frame, client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK)
+					return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
+				if(write_callback(encoder, aspect->page.body, aspect->page.body_len, 0, current_frame, client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK)
+					return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
+			}
+		}
+	}
+	else if(is_metadata && current_frame == 0 && samples == 0 && bytes == 4 && 0 == memcmp(buffer, FLAC__STREAM_SYNC_STRING, sizeof(FLAC__STREAM_SYNC_STRING))) {
+		aspect->seen_magic = true;
+	}
+	else {
+		/*
+		 * If we get here, our assumption about the way write callbacks happen
+		 * explained above is wrong
+		 */
+		FLAC__ASSERT(0);
+		return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
+	}
+
+	aspect->samples_written += samples;
+
+	return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
+}
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/ogg_helper.c
@@ -1,0 +1,210 @@
+/* libFLAC - Free Lossless Audio Codec
+ * Copyright (C) 2004-2009  Josh Coalson
+ * Copyright (C) 2011-2014  Xiph.Org Foundation
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdlib.h> /* for malloc() */
+#include <string.h> /* for memcmp(), memcpy() */
+#include "FLAC/assert.h"
+#include "share/alloc.h"
+#include "private/ogg_helper.h"
+#include "protected/stream_encoder.h"
+
+
+static FLAC__bool full_read_(FLAC__StreamEncoder *encoder, FLAC__byte *buffer, size_t bytes, FLAC__StreamEncoderReadCallback read_callback, void *client_data)
+{
+	while(bytes > 0) {
+		size_t bytes_read = bytes;
+		switch(read_callback(encoder, buffer, &bytes_read, client_data)) {
+			case FLAC__STREAM_ENCODER_READ_STATUS_CONTINUE:
+				bytes -= bytes_read;
+				buffer += bytes_read;
+				break;
+			case FLAC__STREAM_ENCODER_READ_STATUS_END_OF_STREAM:
+				if(bytes_read == 0) {
+					encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR;
+					return false;
+				}
+				bytes -= bytes_read;
+				buffer += bytes_read;
+				break;
+			case FLAC__STREAM_ENCODER_READ_STATUS_ABORT:
+				encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
+				return false;
+			case FLAC__STREAM_ENCODER_READ_STATUS_UNSUPPORTED:
+				return false;
+			default:
+				/* double protection: */
+				FLAC__ASSERT(0);
+				encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
+				return false;
+		}
+	}
+
+	return true;
+}
+
+void simple_ogg_page__init(ogg_page *page)
+{
+	page->header = 0;
+	page->header_len = 0;
+	page->body = 0;
+	page->body_len = 0;
+}
+
+void simple_ogg_page__clear(ogg_page *page)
+{
+	if(page->header)
+		free(page->header);
+	if(page->body)
+		free(page->body);
+	simple_ogg_page__init(page);
+}
+
+FLAC__bool simple_ogg_page__get_at(FLAC__StreamEncoder *encoder, FLAC__uint64 position, ogg_page *page, FLAC__StreamEncoderSeekCallback seek_callback, FLAC__StreamEncoderReadCallback read_callback, void *client_data)
+{
+	static const unsigned OGG_HEADER_FIXED_PORTION_LEN = 27;
+	static const unsigned OGG_MAX_HEADER_LEN = 27/*OGG_HEADER_FIXED_PORTION_LEN*/ + 255;
+	FLAC__byte crc[4];
+	FLAC__StreamEncoderSeekStatus seek_status;
+
+	FLAC__ASSERT(page->header == 0);
+	FLAC__ASSERT(page->header_len == 0);
+	FLAC__ASSERT(page->body == 0);
+	FLAC__ASSERT(page->body_len == 0);
+
+	/* move the stream pointer to the supposed beginning of the page */
+	if(0 == seek_callback)
+		return false;
+	if((seek_status = seek_callback((FLAC__StreamEncoder*)encoder, position, client_data)) != FLAC__STREAM_ENCODER_SEEK_STATUS_OK) {
+		if(seek_status == FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR)
+			encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
+		return false;
+	}
+
+	/* allocate space for the page header */
+	if(0 == (page->header = safe_malloc_(OGG_MAX_HEADER_LEN))) {
+		encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR;
+		return false;
+	}
+
+	/* read in the fixed part of the page header (up to but not including
+	 * the segment table */
+	if(!full_read_(encoder, page->header, OGG_HEADER_FIXED_PORTION_LEN, read_callback, client_data))
+		return false;
+
+	page->header_len = OGG_HEADER_FIXED_PORTION_LEN + page->header[26];
+
+	/* check to see if it's a correct, "simple" page (one packet only) */
+	if(
+		memcmp(page->header, "OggS", 4) ||               /* doesn't start with OggS */
+		(page->header[5] & 0x01) ||                      /* continued packet */
+		memcmp(page->header+6, "\0\0\0\0\0\0\0\0", 8) || /* granulepos is non-zero */
+		page->header[26] == 0                            /* packet is 0-size */
+	) {
+		encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR;
+		return false;
+	}
+
+	/* read in the segment table */
+	if(!full_read_(encoder, page->header + OGG_HEADER_FIXED_PORTION_LEN, page->header[26], read_callback, client_data))
+		return false;
+
+	{
+		unsigned i;
+
+		/* check to see that it specifies a single packet */
+		for(i = 0; i < (unsigned)page->header[26] - 1; i++) {
+			if(page->header[i + OGG_HEADER_FIXED_PORTION_LEN] != 255) {
+				encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR;
+				return false;
+			}
+		}
+
+		page->body_len = 255 * i + page->header[i + OGG_HEADER_FIXED_PORTION_LEN];
+	}
+
+	/* allocate space for the page body */
+	if(0 == (page->body = safe_malloc_(page->body_len))) {
+		encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR;
+		return false;
+	}
+
+	/* read in the page body */
+	if(!full_read_(encoder, page->body, page->body_len, read_callback, client_data))
+		return false;
+
+	/* check the CRC */
+	memcpy(crc, page->header+22, 4);
+	ogg_page_checksum_set(page);
+	if(memcmp(crc, page->header+22, 4)) {
+		encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR;
+		return false;
+	}
+
+	return true;
+}
+
+FLAC__bool simple_ogg_page__set_at(FLAC__StreamEncoder *encoder, FLAC__uint64 position, ogg_page *page, FLAC__StreamEncoderSeekCallback seek_callback, FLAC__StreamEncoderWriteCallback write_callback, void *client_data)
+{
+	FLAC__StreamEncoderSeekStatus seek_status;
+
+	FLAC__ASSERT(page->header != 0);
+	FLAC__ASSERT(page->header_len != 0);
+	FLAC__ASSERT(page->body != 0);
+	FLAC__ASSERT(page->body_len != 0);
+
+	/* move the stream pointer to the supposed beginning of the page */
+	if(0 == seek_callback)
+		return false;
+	if((seek_status = seek_callback((FLAC__StreamEncoder*)encoder, position, client_data)) != FLAC__STREAM_ENCODER_SEEK_STATUS_OK) {
+		if(seek_status == FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR)
+			encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
+		return false;
+	}
+
+	ogg_page_checksum_set(page);
+
+	/* re-write the page */
+	if(write_callback((FLAC__StreamEncoder*)encoder, page->header, page->header_len, 0, 0, client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) {
+		encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
+		return false;
+	}
+	if(write_callback((FLAC__StreamEncoder*)encoder, page->body, page->body_len, 0, 0, client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) {
+		encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
+		return false;
+	}
+
+	return true;
+}
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/ogg_mapping.c
@@ -1,0 +1,48 @@
+/* libFLAC - Free Lossless Audio Codec
+ * Copyright (C) 2004-2009  Josh Coalson
+ * Copyright (C) 2011-2014  Xiph.Org Foundation
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "private/ogg_mapping.h"
+
+const unsigned FLAC__OGG_MAPPING_PACKET_TYPE_LEN = 8; /* bits */
+
+const FLAC__byte FLAC__OGG_MAPPING_FIRST_HEADER_PACKET_TYPE = 0x7f;
+
+const FLAC__byte * const FLAC__OGG_MAPPING_MAGIC = (const FLAC__byte * const)"FLAC";
+
+const unsigned FLAC__OGG_MAPPING_VERSION_MAJOR_LEN = 8; /* bits */
+const unsigned FLAC__OGG_MAPPING_VERSION_MINOR_LEN = 8; /* bits */
+
+const unsigned FLAC__OGG_MAPPING_NUM_HEADERS_LEN = 16; /* bits */
--- a/sys/src/cmd/audio/libFLAC/private/all.h
+++ b/sys/src/cmd/audio/libFLAC/private/all.h
@@ -1,5 +1,6 @@
 /* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2000,2001,2002,2003,2004  Josh Coalson
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2014  Xiph.Org Foundation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -32,11 +33,13 @@
 #ifndef FLAC__PRIVATE__ALL_H
 #define FLAC__PRIVATE__ALL_H
 
-#include "bitbuffer.h"
 #include "bitmath.h"
+#include "bitreader.h"
+#include "bitwriter.h"
 #include "cpu.h"
 #include "crc.h"
 #include "fixed.h"
+#include "float.h"
 #include "format.h"
 #include "lpc.h"
 #include "md5.h"
--- a/sys/src/cmd/audio/libFLAC/private/bitbuffer.h
+++ /dev/null
@@ -1,159 +1,0 @@
-/* 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
--- a/sys/src/cmd/audio/libFLAC/private/bitmath.h
+++ b/sys/src/cmd/audio/libFLAC/private/bitmath.h
@@ -1,5 +1,6 @@
 /* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2001,2002,2003,2004  Josh Coalson
+ * Copyright (C) 2001-2009  Josh Coalson
+ * Copyright (C) 2011-2014  Xiph.Org Foundation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -33,8 +34,152 @@
 #define FLAC__PRIVATE__BITMATH_H
 
 #include "FLAC/ordinals.h"
+#include "FLAC/assert.h"
 
-unsigned FLAC__bitmath_ilog2(unsigned v);
+/* for CHAR_BIT */
+#include <limits.h>
+#include "share/compat.h"
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1400)
+#include <intrin.h> /* for _BitScanReverse* */
+#endif
+
+/* Will never be emitted for MSVC, GCC, Intel compilers */
+static inline unsigned int FLAC__clz_soft_uint32(unsigned int word)
+{
+    static const unsigned char byte_to_unary_table[] = {
+    8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    };
+
+    return (word) > 0xffffff ? byte_to_unary_table[(word) >> 24] :
+    (word) > 0xffff ? byte_to_unary_table[(word) >> 16] + 8 :
+    (word) > 0xff ? byte_to_unary_table[(word) >> 8] + 16 :
+    byte_to_unary_table[(word)] + 24;
+}
+
+static inline unsigned int FLAC__clz_uint32(FLAC__uint32 v)
+{
+/* Never used with input 0 */
+    FLAC__ASSERT(v > 0);
+#if defined(__INTEL_COMPILER)
+    return _bit_scan_reverse(v) ^ 31U;
+#elif defined(__GNUC__) && (__GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
+/* This will translate either to (bsr ^ 31U), clz , ctlz, cntlz, lzcnt depending on
+ * -march= setting or to a software routine in exotic machines. */
+    return __builtin_clz(v);
+#elif defined(_MSC_VER) && (_MSC_VER >= 1400)
+    {
+        unsigned long idx;
+        _BitScanReverse(&idx, v);
+        return idx ^ 31U;
+    }
+#else
+    return FLAC__clz_soft_uint32(v);
+#endif
+}
+
+/* This one works with input 0 */
+static inline unsigned int FLAC__clz2_uint32(FLAC__uint32 v)
+{
+    if (!v)
+        return 32;
+    return FLAC__clz_uint32(v);
+}
+
+/* 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
+ */
+
+static inline unsigned FLAC__bitmath_ilog2(FLAC__uint32 v)
+{
+    FLAC__ASSERT(v > 0);
+#if defined(__INTEL_COMPILER)
+    return _bit_scan_reverse(v);
+#elif defined(_MSC_VER) && (_MSC_VER >= 1400)
+    {
+        unsigned long idx;
+        _BitScanReverse(&idx, v);
+        return idx;
+    }
+#else
+    return sizeof(FLAC__uint32) * CHAR_BIT  - 1 - FLAC__clz_uint32(v);
+#endif
+}
+
+
+#ifdef FLAC__INTEGER_ONLY_LIBRARY /* Unused otherwise */
+
+static inline unsigned FLAC__bitmath_ilog2_wide(FLAC__uint64 v)
+{
+    FLAC__ASSERT(v > 0);
+#if defined(__GNUC__) && (__GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
+    return sizeof(FLAC__uint64) * CHAR_BIT - 1 - __builtin_clzll(v);
+/* Sorry, only supported in x64/Itanium.. and both have fast FPU which makes integer-only encoder pointless */
+#elif (defined(_MSC_VER) && (_MSC_VER >= 1400)) && (defined(_M_IA64) || defined(_M_X64))
+    {
+        unsigned long idx;
+        _BitScanReverse64(&idx, v);
+        return idx;
+    }
+#else
+/*  Brain-damaged compilers will use the fastest possible way that is,
+    de Bruijn sequences (http://supertech.csail.mit.edu/papers/debruijn.pdf)
+    (C) Timothy B. Terriberry ([email protected]) 2001-2009 CC0 (Public domain).
+*/
+    {
+        static const unsigned char DEBRUIJN_IDX64[64]={
+            0, 1, 2, 7, 3,13, 8,19, 4,25,14,28, 9,34,20,40,
+            5,17,26,38,15,46,29,48,10,31,35,54,21,50,41,57,
+            63, 6,12,18,24,27,33,39,16,37,45,47,30,53,49,56,
+            62,11,23,32,36,44,52,55,61,22,43,51,60,42,59,58
+        };
+        v|= v>>1;
+        v|= v>>2;
+        v|= v>>4;
+        v|= v>>8;
+        v|= v>>16;
+        v|= v>>32;
+        v= (v>>1)+1;
+        return DEBRUIJN_IDX64[v*0x218A392CD3D5DBF>>58&0x3F];
+    }
+#endif
+}
+#endif
+
 unsigned FLAC__bitmath_silog2(int v);
 unsigned FLAC__bitmath_silog2_wide(FLAC__int64 v);
 
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/private/bitreader.h
@@ -1,0 +1,91 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2014  Xiph.Org Foundation
+ *
+ * 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__BITREADER_H
+#define FLAC__PRIVATE__BITREADER_H
+
+#include <stdio.h> /* for FILE */
+#include "FLAC/ordinals.h"
+#include "cpu.h"
+
+/*
+ * opaque structure definition
+ */
+struct FLAC__BitReader;
+typedef struct FLAC__BitReader FLAC__BitReader;
+
+typedef FLAC__bool (*FLAC__BitReaderReadCallback)(FLAC__byte buffer[], size_t *bytes, void *client_data);
+
+/*
+ * construction, deletion, initialization, etc functions
+ */
+FLAC__BitReader *FLAC__bitreader_new(void);
+void FLAC__bitreader_delete(FLAC__BitReader *br);
+FLAC__bool FLAC__bitreader_init(FLAC__BitReader *br, FLAC__BitReaderReadCallback rcb, void *cd);
+void FLAC__bitreader_free(FLAC__BitReader *br); /* does not 'free(br)' */
+FLAC__bool FLAC__bitreader_clear(FLAC__BitReader *br);
+void FLAC__bitreader_dump(const FLAC__BitReader *br, FILE *out);
+
+/*
+ * CRC functions
+ */
+void FLAC__bitreader_reset_read_crc16(FLAC__BitReader *br, FLAC__uint16 seed);
+FLAC__uint16 FLAC__bitreader_get_read_crc16(FLAC__BitReader *br);
+
+/*
+ * info functions
+ */
+FLAC__bool FLAC__bitreader_is_consumed_byte_aligned(const FLAC__BitReader *br);
+unsigned FLAC__bitreader_bits_left_for_byte_alignment(const FLAC__BitReader *br);
+unsigned FLAC__bitreader_get_input_bits_unconsumed(const FLAC__BitReader *br);
+
+/*
+ * read functions
+ */
+
+FLAC__bool FLAC__bitreader_read_raw_uint32(FLAC__BitReader *br, FLAC__uint32 *val, unsigned bits);
+FLAC__bool FLAC__bitreader_read_raw_int32(FLAC__BitReader *br, FLAC__int32 *val, unsigned bits);
+FLAC__bool FLAC__bitreader_read_raw_uint64(FLAC__BitReader *br, FLAC__uint64 *val, unsigned bits);
+FLAC__bool FLAC__bitreader_read_uint32_little_endian(FLAC__BitReader *br, FLAC__uint32 *val); /*only for bits=32*/
+FLAC__bool FLAC__bitreader_skip_bits_no_crc(FLAC__BitReader *br, unsigned bits); /* WATCHOUT: does not CRC the skipped data! */ /*@@@@ add to unit tests */
+FLAC__bool FLAC__bitreader_skip_byte_block_aligned_no_crc(FLAC__BitReader *br, unsigned nvals); /* WATCHOUT: does not CRC the read data! */
+FLAC__bool FLAC__bitreader_read_byte_block_aligned_no_crc(FLAC__BitReader *br, FLAC__byte *val, unsigned nvals); /* WATCHOUT: does not CRC the read data! */
+FLAC__bool FLAC__bitreader_read_unary_unsigned(FLAC__BitReader *br, unsigned *val);
+FLAC__bool FLAC__bitreader_read_rice_signed(FLAC__BitReader *br, int *val, unsigned parameter);
+FLAC__bool FLAC__bitreader_read_rice_signed_block(FLAC__BitReader *br, int vals[], unsigned nvals, unsigned parameter);
+#if 0 /* UNUSED */
+FLAC__bool FLAC__bitreader_read_golomb_signed(FLAC__BitReader *br, int *val, unsigned parameter);
+FLAC__bool FLAC__bitreader_read_golomb_unsigned(FLAC__BitReader *br, unsigned *val, unsigned parameter);
+#endif
+FLAC__bool FLAC__bitreader_read_utf8_uint32(FLAC__BitReader *br, FLAC__uint32 *val, FLAC__byte *raw, unsigned *rawlen);
+FLAC__bool FLAC__bitreader_read_utf8_uint64(FLAC__BitReader *br, FLAC__uint64 *val, FLAC__byte *raw, unsigned *rawlen);
+#endif
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/private/bitwriter.h
@@ -1,0 +1,104 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2014  Xiph.Org Foundation
+ *
+ * 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__BITWRITER_H
+#define FLAC__PRIVATE__BITWRITER_H
+
+#include <stdio.h> /* for FILE */
+#include "FLAC/ordinals.h"
+
+/*
+ * opaque structure definition
+ */
+struct FLAC__BitWriter;
+typedef struct FLAC__BitWriter FLAC__BitWriter;
+
+/*
+ * construction, deletion, initialization, etc functions
+ */
+FLAC__BitWriter *FLAC__bitwriter_new(void);
+void FLAC__bitwriter_delete(FLAC__BitWriter *bw);
+FLAC__bool FLAC__bitwriter_init(FLAC__BitWriter *bw);
+void FLAC__bitwriter_free(FLAC__BitWriter *bw); /* does not 'free(buffer)' */
+void FLAC__bitwriter_clear(FLAC__BitWriter *bw);
+void FLAC__bitwriter_dump(const FLAC__BitWriter *bw, FILE *out);
+
+/*
+ * CRC functions
+ *
+ * non-const *bw because they have to cal FLAC__bitwriter_get_buffer()
+ */
+FLAC__bool FLAC__bitwriter_get_write_crc16(FLAC__BitWriter *bw, FLAC__uint16 *crc);
+FLAC__bool FLAC__bitwriter_get_write_crc8(FLAC__BitWriter *bw, FLAC__byte *crc);
+
+/*
+ * info functions
+ */
+FLAC__bool FLAC__bitwriter_is_byte_aligned(const FLAC__BitWriter *bw);
+unsigned FLAC__bitwriter_get_input_bits_unconsumed(const FLAC__BitWriter *bw); /* can be called anytime, returns total # of bits unconsumed */
+
+/*
+ * direct buffer access
+ *
+ * there may be no calls on the bitwriter between get and release.
+ * the bitwriter continues to own the returned buffer.
+ * before get, bitwriter MUST be byte aligned: check with FLAC__bitwriter_is_byte_aligned()
+ */
+FLAC__bool FLAC__bitwriter_get_buffer(FLAC__BitWriter *bw, const FLAC__byte **buffer, size_t *bytes);
+void FLAC__bitwriter_release_buffer(FLAC__BitWriter *bw);
+
+/*
+ * write functions
+ */
+FLAC__bool FLAC__bitwriter_write_zeroes(FLAC__BitWriter *bw, unsigned bits);
+FLAC__bool FLAC__bitwriter_write_raw_uint32(FLAC__BitWriter *bw, FLAC__uint32 val, unsigned bits);
+FLAC__bool FLAC__bitwriter_write_raw_int32(FLAC__BitWriter *bw, FLAC__int32 val, unsigned bits);
+FLAC__bool FLAC__bitwriter_write_raw_uint64(FLAC__BitWriter *bw, FLAC__uint64 val, unsigned bits);
+FLAC__bool FLAC__bitwriter_write_raw_uint32_little_endian(FLAC__BitWriter *bw, FLAC__uint32 val); /*only for bits=32*/
+FLAC__bool FLAC__bitwriter_write_byte_block(FLAC__BitWriter *bw, const FLAC__byte vals[], unsigned nvals);
+FLAC__bool FLAC__bitwriter_write_unary_unsigned(FLAC__BitWriter *bw, unsigned val);
+unsigned FLAC__bitwriter_rice_bits(FLAC__int32 val, unsigned parameter);
+#if 0 /* UNUSED */
+unsigned FLAC__bitwriter_golomb_bits_signed(int val, unsigned parameter);
+unsigned FLAC__bitwriter_golomb_bits_unsigned(unsigned val, unsigned parameter);
+#endif
+FLAC__bool FLAC__bitwriter_write_rice_signed(FLAC__BitWriter *bw, FLAC__int32 val, unsigned parameter);
+FLAC__bool FLAC__bitwriter_write_rice_signed_block(FLAC__BitWriter *bw, const FLAC__int32 *vals, unsigned nvals, unsigned parameter);
+#if 0 /* UNUSED */
+FLAC__bool FLAC__bitwriter_write_golomb_signed(FLAC__BitWriter *bw, int val, unsigned parameter);
+FLAC__bool FLAC__bitwriter_write_golomb_unsigned(FLAC__BitWriter *bw, unsigned val, unsigned parameter);
+#endif
+FLAC__bool FLAC__bitwriter_write_utf8_uint32(FLAC__BitWriter *bw, FLAC__uint32 val);
+FLAC__bool FLAC__bitwriter_write_utf8_uint64(FLAC__BitWriter *bw, FLAC__uint64 val);
+FLAC__bool FLAC__bitwriter_zero_pad_to_byte_boundary(FLAC__BitWriter *bw);
+
+#endif
--- a/sys/src/cmd/audio/libFLAC/private/cpu.h
+++ b/sys/src/cmd/audio/libFLAC/private/cpu.h
@@ -1,5 +1,6 @@
 /* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2001,2002,2003,2004  Josh Coalson
+ * Copyright (C) 2001-2009  Josh Coalson
+ * Copyright (C) 2011-2014  Xiph.Org Foundation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -38,56 +39,130 @@
 #include <config.h>
 #endif
 
+#if defined FLAC__HAS_X86INTRIN
+/* SSE intrinsics support by ICC/MSVC/GCC */
+#if defined __INTEL_COMPILER
+  #define FLAC__SSE_TARGET(x)
+  #define FLAC__SSE_SUPPORTED 1
+  #define FLAC__SSE2_SUPPORTED 1
+  #if (__INTEL_COMPILER >= 1000) /* Intel C++ Compiler 10.0 */
+    #define FLAC__SSSE3_SUPPORTED 1
+    #define FLAC__SSE4_1_SUPPORTED 1
+  #endif
+  #if (__INTEL_COMPILER >= 1110) /* Intel C++ Compiler 11.1 */
+    #define FLAC__AVX_SUPPORTED 1
+  #endif
+  #if (__INTEL_COMPILER >= 1300) /* Intel C++ Compiler 13.0 */
+    #define FLAC__AVX2_SUPPORTED 1
+    #define FLAC__FMA_SUPPORTED 1
+  #endif
+#elif defined _MSC_VER
+  #define FLAC__SSE_TARGET(x)
+  #define FLAC__SSE_SUPPORTED 1
+  #define FLAC__SSE2_SUPPORTED 1
+  #if (_MSC_VER >= 1500) /* MS Visual Studio 2008 */
+    #define FLAC__SSSE3_SUPPORTED 1
+    #define FLAC__SSE4_1_SUPPORTED 1
+  #endif
+  #if (_MSC_FULL_VER >= 160040219) /* MS Visual Studio 2010 SP1 */
+    #define FLAC__AVX_SUPPORTED 1
+  #endif
+  #if (_MSC_VER >= 1700) /* MS Visual Studio 2012 */
+    #define FLAC__AVX2_SUPPORTED 1
+    #define FLAC__FMA_SUPPORTED 1
+  #endif
+#elif defined __GNUC__
+  #if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)) /* since GCC 4.9 -msse.. compiler options aren't necessary */
+    #define FLAC__SSE_TARGET(x) __attribute__ ((__target__ (x)))
+    #define FLAC__SSE_SUPPORTED 1
+    #define FLAC__SSE2_SUPPORTED 1
+    #define FLAC__SSSE3_SUPPORTED 1
+    #define FLAC__SSE4_1_SUPPORTED 1
+    #define FLAC__AVX_SUPPORTED 1
+    #define FLAC__AVX2_SUPPORTED 1
+    #define FLAC__FMA_SUPPORTED 1
+  #else /* for GCC older than 4.9 */
+    #define FLAC__SSE_TARGET(x)
+    #ifdef __SSE__
+      #define FLAC__SSE_SUPPORTED 1
+    #endif
+    #ifdef __SSE2__
+      #define FLAC__SSE2_SUPPORTED 1
+    #endif
+    #ifdef __SSSE3__
+      #define FLAC__SSSE3_SUPPORTED 1
+    #endif
+    #ifdef __SSE4_1__
+      #define FLAC__SSE4_1_SUPPORTED 1
+    #endif
+    #ifdef __AVX__
+      #define FLAC__AVX_SUPPORTED 1
+    #endif
+    #ifdef __AVX2__
+      #define FLAC__AVX2_SUPPORTED 1
+    #endif
+    #ifdef __FMA__
+      #define FLAC__FMA_SUPPORTED 1
+    #endif
+  #endif /* GCC version */
+#endif /* compiler version */
+#endif /* intrinsics support */
+
 typedef enum {
 	FLAC__CPUINFO_TYPE_IA32,
-	FLAC__CPUINFO_TYPE_PPC,
+	FLAC__CPUINFO_TYPE_X86_64,
 	FLAC__CPUINFO_TYPE_UNKNOWN
 } FLAC__CPUInfo_Type;
 
+#if defined FLAC__CPU_IA32
 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;
 
+	FLAC__bool sse3;
+	FLAC__bool ssse3;
+	FLAC__bool sse41;
+	FLAC__bool sse42;
+	FLAC__bool avx;
+	FLAC__bool avx2;
+	FLAC__bool fma;
+} FLAC__CPUInfo_IA32;
+#elif defined FLAC__CPU_X86_64
 typedef struct {
-	FLAC__bool altivec;
-} FLAC__CPUInfo_PPC;
+	FLAC__bool sse3;
+	FLAC__bool ssse3;
+	FLAC__bool sse41;
+	FLAC__bool sse42;
+	FLAC__bool avx;
+	FLAC__bool avx2;
+	FLAC__bool fma;
+} FLAC__CPUInfo_x86;
+#endif
 
-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;
+#if defined FLAC__CPU_IA32
+	FLAC__CPUInfo_IA32 ia32;
+#elif defined FLAC__CPU_X86_64
+	FLAC__CPUInfo_x86 x86;
+#endif
 } 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
+# if defined FLAC__CPU_IA32 && defined FLAC__HAS_NASM
+FLAC__uint32 FLAC__cpu_have_cpuid_asm_ia32(void);
+void         FLAC__cpu_info_asm_ia32(FLAC__uint32 *flags_edx, FLAC__uint32 *flags_ecx);
+# endif
+# if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && defined FLAC__HAS_X86INTRIN
+FLAC__uint32 FLAC__cpu_have_cpuid_x86(void);
+void         FLAC__cpu_info_x86(FLAC__uint32 level, FLAC__uint32 *eax, FLAC__uint32 *ebx, FLAC__uint32 *ecx, FLAC__uint32 *edx);
+FLAC__uint32 FLAC__cpu_xgetbv_x86(void);
+# endif
 #endif
 
 #endif
--- a/sys/src/cmd/audio/libFLAC/private/crc.h
+++ b/sys/src/cmd/audio/libFLAC/private/crc.h
@@ -1,5 +1,6 @@
 /* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2000,2001,2002,2003,2004  Josh Coalson
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2014  Xiph.Org Foundation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -48,10 +49,14 @@
 ** 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);
+extern unsigned const FLAC__crc16_table[256];
+
+#define FLAC__CRC16_UPDATE(data, crc) ((((crc)<<8) & 0xffff) ^ FLAC__crc16_table[((crc)>>8) ^ (data)])
+/* this alternate may be faster on some systems/compilers */
+#if 0
+#define FLAC__CRC16_UPDATE(data, crc) ((((crc)<<8) ^ FLAC__crc16_table[((crc)>>8) ^ (data)]) & 0xffff)
+#endif
+
+unsigned FLAC__crc16(const FLAC__byte *data, unsigned len);
 
 #endif
--- a/sys/src/cmd/audio/libFLAC/private/fixed.h
+++ b/sys/src/cmd/audio/libFLAC/private/fixed.h
@@ -1,5 +1,6 @@
 /* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2000,2001,2002,2003,2004  Josh Coalson
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2014  Xiph.Org Foundation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -32,12 +33,14 @@
 #ifndef FLAC__PRIVATE__FIXED_H
 #define FLAC__PRIVATE__FIXED_H
 
-#include "FLAC/format.h"
-
 #ifdef HAVE_CONFIG_H
 #include <config.h>
 #endif
 
+#include "private/cpu.h"
+#include "private/float.h"
+#include "FLAC/format.h"
+
 /*
  *	FLAC__fixed_compute_best_predictor()
  *	--------------------------------------------------------------------
@@ -50,15 +53,28 @@
  *	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]);
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+unsigned FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+unsigned FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+# ifndef FLAC__NO_ASM
+#  if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && defined FLAC__HAS_X86INTRIN
+#   ifdef FLAC__SSE2_SUPPORTED
+unsigned FLAC__fixed_compute_best_predictor_intrin_sse2(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER + 1]);
+unsigned FLAC__fixed_compute_best_predictor_wide_intrin_sse2(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER + 1]);
+#   endif
+#   ifdef FLAC__SSSE3_SUPPORTED
+unsigned FLAC__fixed_compute_best_predictor_intrin_ssse3(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+unsigned FLAC__fixed_compute_best_predictor_wide_intrin_ssse3(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER + 1]);
+#   endif
+#  endif
+#  if defined FLAC__CPU_IA32 && defined FLAC__HAS_NASM
+unsigned FLAC__fixed_compute_best_predictor_asm_ia32_mmx_cmov(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+#  endif
+# endif
+#else
+unsigned FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], unsigned data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+unsigned FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], unsigned data_len, FLAC__fixedpoint 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()
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/private/float.h
@@ -1,0 +1,98 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2004-2009  Josh Coalson
+ * Copyright (C) 2011-2014  Xiph.Org Foundation
+ *
+ * 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__FLOAT_H
+#define FLAC__PRIVATE__FLOAT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "FLAC/ordinals.h"
+
+/*
+ * These typedefs make it easier to ensure that integer versions of
+ * the library really only contain integer operations.  All the code
+ * in libFLAC should use FLAC__float and FLAC__double in place of
+ * float and double, and be protected by checks of the macro
+ * FLAC__INTEGER_ONLY_LIBRARY.
+ *
+ * FLAC__real is the basic floating point type used in LPC analysis.
+ */
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+typedef double FLAC__double;
+typedef float FLAC__float;
+/*
+ * WATCHOUT: changing FLAC__real will change the signatures of many
+ * functions that have assembly language equivalents and break them.
+ */
+typedef float FLAC__real;
+#else
+/*
+ * The convention for FLAC__fixedpoint is to use the upper 16 bits
+ * for the integer part and lower 16 bits for the fractional part.
+ */
+typedef FLAC__int32 FLAC__fixedpoint;
+extern const FLAC__fixedpoint FLAC__FP_ZERO;
+extern const FLAC__fixedpoint FLAC__FP_ONE_HALF;
+extern const FLAC__fixedpoint FLAC__FP_ONE;
+extern const FLAC__fixedpoint FLAC__FP_LN2;
+extern const FLAC__fixedpoint FLAC__FP_E;
+
+#define FLAC__fixedpoint_trunc(x) ((x)>>16)
+
+#define FLAC__fixedpoint_mul(x, y) ( (FLAC__fixedpoint) ( ((FLAC__int64)(x)*(FLAC__int64)(y)) >> 16 ) )
+
+#define FLAC__fixedpoint_div(x, y) ( (FLAC__fixedpoint) ( ( ((FLAC__int64)(x)<<32) / (FLAC__int64)(y) ) >> 16 ) )
+
+/*
+ *	FLAC__fixedpoint_log2()
+ *	--------------------------------------------------------------------
+ *	Returns the base-2 logarithm of the fixed-point number 'x' using an
+ *	algorithm by Knuth for x >= 1.0
+ *
+ *	'fracbits' is the number of fractional bits of 'x'.  'fracbits' must
+ *	be < 32 and evenly divisible by 4 (0 is OK but not very precise).
+ *
+ *	'precision' roughly limits the number of iterations that are done;
+ *	use (unsigned)(-1) for maximum precision.
+ *
+ *	If 'x' is less than one -- that is, x < (1<<fracbits) -- then this
+ *	function will punt and return 0.
+ *
+ *	The return value will also have 'fracbits' fractional bits.
+ */
+FLAC__uint32 FLAC__fixedpoint_log2(FLAC__uint32 x, unsigned fracbits, unsigned precision);
+
+#endif
+
+#endif
--- a/sys/src/cmd/audio/libFLAC/private/format.h
+++ b/sys/src/cmd/audio/libFLAC/private/format.h
@@ -1,5 +1,6 @@
 /* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2000,2001,2002,2003,2004  Josh Coalson
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2014  Xiph.Org Foundation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
--- a/sys/src/cmd/audio/libFLAC/private/lpc.h
+++ b/sys/src/cmd/audio/libFLAC/private/lpc.h
@@ -1,5 +1,6 @@
 /* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2000,2001,2002,2003,2004  Josh Coalson
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2014  Xiph.Org Foundation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -32,13 +33,30 @@
 #ifndef FLAC__PRIVATE__LPC_H
 #define FLAC__PRIVATE__LPC_H
 
-#include "FLAC/format.h"
-
 #ifdef HAVE_CONFIG_H
 #include <config.h>
 #endif
 
+#include "private/cpu.h"
+#include "private/float.h"
+#include "FLAC/format.h"
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+
 /*
+ *	FLAC__lpc_window_data()
+ *	--------------------------------------------------------------------
+ *	Applies the given window to the data.
+ *  OPT: asm implementation
+ *
+ *	IN in[0,data_len-1]
+ *	IN window[0,data_len-1]
+ *	OUT out[0,lag-1]
+ *	IN data_len
+ */
+void FLAC__lpc_window_data(const FLAC__int32 in[], const FLAC__real window[], FLAC__real out[], unsigned data_len);
+
+/*
  *	FLAC__lpc_compute_autocorrelation()
  *	--------------------------------------------------------------------
  *	Compute the autocorrelation for lags between 0 and lag-1.
@@ -52,15 +70,24 @@
  */
 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
+#  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[]);
+void FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_16(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]);
+#    endif
+#  endif
+#  if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && defined FLAC__HAS_X86INTRIN
+#    ifdef FLAC__SSE_SUPPORTED
+void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_4(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_8(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_12(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_16(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]);
+#    endif
+#  endif
 #endif
-#endif
 
 /*
  *	FLAC__lpc_compute_lp_coefficients()
@@ -74,13 +101,16 @@
  *	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
+ *	OUT error[0,max_order-1]                   error for each order (more
+ *	                                           specifically, the variance of
+ *	                                           the error signal times # of
+ *	                                           samples in the signal)
  *
  *	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[]);
+void FLAC__lpc_compute_lp_coefficients(const FLAC__real autoc[], unsigned *max_order, FLAC__real lp_coeff[][FLAC__MAX_LPC_ORDER], FLAC__double error[]);
 
 /*
  *	FLAC__lpc_quantize_coefficients()
@@ -117,17 +147,35 @@
  *	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[]);
+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[]);
+#  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[]);
+void FLAC__lpc_compute_residual_from_qlp_coefficients_wide_asm_ia32(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]);
+#    endif
+#  endif
+#  if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && defined FLAC__HAS_X86INTRIN
+#    ifdef FLAC__SSE2_SUPPORTED
+void FLAC__lpc_compute_residual_from_qlp_coefficients_16_intrin_sse2(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_intrin_sse2(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]);
+#    endif
+#    ifdef FLAC__SSE4_1_SUPPORTED
+void FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_sse41(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_intrin_sse41(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]);
+#    endif
+#    ifdef FLAC__AVX2_SUPPORTED
+void FLAC__lpc_compute_residual_from_qlp_coefficients_16_intrin_avx2(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_intrin_avx2(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_intrin_avx2(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]);
+#    endif
+#  endif
 #endif
-#endif
-#endif
 
+#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */
+
 /*
  *	FLAC__lpc_restore_signal()
  *	--------------------------------------------------------------------
@@ -146,18 +194,25 @@
 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
+#  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
+void FLAC__lpc_restore_signal_wide_asm_ia32(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]);
+#    endif /* FLAC__HAS_NASM */
+#  endif /* FLAC__CPU_IA32 */
+#  if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && defined FLAC__HAS_X86INTRIN
+#    ifdef FLAC__SSE2_SUPPORTED
+void FLAC__lpc_restore_signal_16_intrin_sse2(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]);
+#    endif
+#    ifdef FLAC__SSE4_1_SUPPORTED
+void FLAC__lpc_restore_signal_wide_intrin_sse41(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]);
+#    endif
+#  endif
+#endif /* FLAC__NO_ASM */
 
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+
 /*
  *	FLAC__lpc_compute_expected_bits_per_residual_sample()
  *	--------------------------------------------------------------------
@@ -168,8 +223,8 @@
  *	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__double FLAC__lpc_compute_expected_bits_per_residual_sample(FLAC__double lpc_error, unsigned total_samples);
+FLAC__double FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(FLAC__double lpc_error, FLAC__double error_scale);
 
 /*
  *	FLAC__lpc_compute_best_order()
@@ -180,9 +235,12 @@
  *	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
+ *	IN overhead_bits_per_order          # of bits overhead for each increased LP order
+ *	                                    (includes warmup sample size and quantized LP coefficient)
  *	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);
+unsigned FLAC__lpc_compute_best_order(const FLAC__double lpc_error[], unsigned max_order, unsigned total_samples, unsigned overhead_bits_per_order);
+
+#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */
 
 #endif
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/private/macros.h
@@ -1,0 +1,77 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2012-2014  Xiph.org Foundation
+ *
+ * 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__MACROS_H
+#define FLAC__PRIVATE__MACROS_H
+
+#ifdef Plan9
+#define flac_min(x,y)	MIN(x,y)
+#define flac_max(x,y)	MAX(x,y)
+#endif
+
+#if defined(__GNUC__) && (__GNUC__ > 4 || ( __GNUC__ == 4 && __GNUC_MINOR__ >= 3))
+
+#define flac_max(a,b) \
+    ({ __typeof__ (a) _a = (a); \
+    __typeof__ (b) _b = (b); \
+    _a > _b ? _a : _b; })
+
+#define MIN_PASTE(A,B) A##B
+#define MIN_IMPL(A,B,L) ({ \
+    __typeof__(A) MIN_PASTE(__a,L) = (A); \
+    __typeof__(B) MIN_PASTE(__b,L) = (B); \
+    MIN_PASTE(__a,L) < MIN_PASTE(__b,L) ? MIN_PASTE(__a,L) : MIN_PASTE(__b,L); \
+    })
+
+#define flac_min(A,B) MIN_IMPL(A,B,__COUNTER__)
+
+/* Whatever other unix that has sys/param.h */
+#elif defined(HAVE_SYS_PARAM_H)
+#include <sys/param.h>
+#define flac_max(a,b) MAX(a,b)
+#define flac_min(a,b) MIN(a,b)
+
+/* Windows VS has them in stdlib.h.. XXX:Untested */
+#elif defined(_MSC_VER)
+#include <stdlib.h>
+#define flac_max(a,b) __max(a,b)
+#define flac_min(a,b) __min(a,b)
+#endif
+
+#ifndef MIN
+#define MIN(x,y)	((x) <= (y) ? (x) : (y))
+#endif
+
+#ifndef MAX
+#define MAX(x,y)	((x) >= (y) ? (x) : (y))
+#endif
+
+#endif
--- a/sys/src/cmd/audio/libFLAC/private/md5.h
+++ b/sys/src/cmd/audio/libFLAC/private/md5.h
@@ -1,3 +1,6 @@
+#ifndef FLAC__PRIVATE__MD5_H
+#define FLAC__PRIVATE__MD5_H
+
 /*
  * This is the header file for the MD5 message-digest algorithm.
  * The algorithm is due to Ron Rivest.  This code was
@@ -20,35 +23,28 @@
  * Still in the public domain.
  *
  * Josh Coalson: made some changes to integrate with libFLAC.
- * Still in the public domain.
+ * Still in the public domain, with no warranty.
  */
 
-#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 {
+typedef union {
+	FLAC__byte *p8;
+	FLAC__int16 *p16;
+	FLAC__int32 *p32;
+} FLAC__multibyte;
+
+typedef struct {
+	FLAC__uint32 in[16];
 	FLAC__uint32 buf[4];
 	FLAC__uint32 bytes[2];
-	FLAC__uint32 in[16];
-	FLAC__byte *internal_buf;
-	unsigned capacity;
-};
+	FLAC__multibyte internal_buf;
+	size_t capacity;
+} FLAC__MD5Context;
 
-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]);
+void FLAC__MD5Init(FLAC__MD5Context *context);
+void FLAC__MD5Final(FLAC__byte digest[16], FLAC__MD5Context *context);
 
-FLAC_API FLAC__bool FLAC__MD5Accumulate(struct FLAC__MD5Context *ctx, const FLAC__int32 * const signal[], unsigned channels, unsigned samples, unsigned bytes_per_sample);
+FLAC__bool FLAC__MD5Accumulate(FLAC__MD5Context *ctx, const FLAC__int32 * const signal[], unsigned channels, unsigned samples, unsigned bytes_per_sample);
 
-#endif /* !MD5_H */
+#endif
--- a/sys/src/cmd/audio/libFLAC/private/memory.h
+++ b/sys/src/cmd/audio/libFLAC/private/memory.h
@@ -1,5 +1,6 @@
 /* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2001,2002,2003,2004  Josh Coalson
+ * Copyright (C) 2001-2009  Josh Coalson
+ * Copyright (C) 2011-2014  Xiph.Org Foundation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -32,8 +33,13 @@
 #ifndef FLAC__PRIVATE__MEMORY_H
 #define FLAC__PRIVATE__MEMORY_H
 
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
 #include <stdlib.h> /* for size_t */
 
+#include "private/float.h"
 #include "FLAC/ordinals.h" /* for FLAC__bool */
 
 /* Returns the unaligned address returned by malloc.
@@ -40,10 +46,13 @@
  * 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);
+FLAC__bool FLAC__memory_alloc_aligned_int32_array(size_t elements, FLAC__int32 **unaligned_pointer, FLAC__int32 **aligned_pointer);
+FLAC__bool FLAC__memory_alloc_aligned_uint32_array(size_t elements, FLAC__uint32 **unaligned_pointer, FLAC__uint32 **aligned_pointer);
+FLAC__bool FLAC__memory_alloc_aligned_uint64_array(size_t elements, FLAC__uint64 **unaligned_pointer, FLAC__uint64 **aligned_pointer);
+FLAC__bool FLAC__memory_alloc_aligned_unsigned_array(size_t elements, unsigned **unaligned_pointer, unsigned **aligned_pointer);
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+FLAC__bool FLAC__memory_alloc_aligned_real_array(size_t elements, FLAC__real **unaligned_pointer, FLAC__real **aligned_pointer);
+#endif
+void *safe_malloc_mul_2op_p(size_t size1, size_t size2);
 
 #endif
--- a/sys/src/cmd/audio/libFLAC/private/metadata.h
+++ b/sys/src/cmd/audio/libFLAC/private/metadata.h
@@ -1,5 +1,6 @@
 /* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2002,2003,2004  Josh Coalson
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2014  Xiph.Org Foundation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -34,7 +35,12 @@
 
 #include "FLAC/metadata.h"
 
+/* WATCHOUT: all malloc()ed data in the block is free()ed; this may not
+ * be a consistent state (e.g. PICTURE) or equivalent to the initial
+ * state after FLAC__metadata_object_new()
+ */
 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/ogg_decoder_aspect.h
@@ -1,0 +1,80 @@
+/* libFLAC - Free Lossless Audio Codec
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2014  Xiph.Org Foundation
+ *
+ * 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__OGG_DECODER_ASPECT_H
+#define FLAC__PRIVATE__OGG_DECODER_ASPECT_H
+
+#include <ogg/ogg.h>
+
+#include "FLAC/ordinals.h"
+#include "FLAC/stream_decoder.h" /* for FLAC__StreamDecoderReadStatus */
+
+typedef struct FLAC__OggDecoderAspect {
+	/* these are storage for values that can be set through the API */
+	FLAC__bool use_first_serial_number;
+	long serial_number;
+
+	/* these are for internal state related to Ogg decoding */
+	ogg_stream_state stream_state;
+	ogg_sync_state sync_state;
+	unsigned version_major, version_minor;
+	FLAC__bool need_serial_number;
+	FLAC__bool end_of_stream;
+	FLAC__bool have_working_page; /* only if true will the following vars be valid */
+	ogg_page working_page;
+	FLAC__bool have_working_packet; /* only if true will the following vars be valid */
+	ogg_packet working_packet; /* as we work through the packet we will move working_packet.packet forward and working_packet.bytes down */
+} FLAC__OggDecoderAspect;
+
+void FLAC__ogg_decoder_aspect_set_serial_number(FLAC__OggDecoderAspect *aspect, long value);
+void FLAC__ogg_decoder_aspect_set_defaults(FLAC__OggDecoderAspect *aspect);
+FLAC__bool FLAC__ogg_decoder_aspect_init(FLAC__OggDecoderAspect *aspect);
+void FLAC__ogg_decoder_aspect_finish(FLAC__OggDecoderAspect *aspect);
+void FLAC__ogg_decoder_aspect_flush(FLAC__OggDecoderAspect *aspect);
+void FLAC__ogg_decoder_aspect_reset(FLAC__OggDecoderAspect *aspect);
+
+typedef enum {
+	FLAC__OGG_DECODER_ASPECT_READ_STATUS_OK = 0,
+	FLAC__OGG_DECODER_ASPECT_READ_STATUS_END_OF_STREAM,
+	FLAC__OGG_DECODER_ASPECT_READ_STATUS_LOST_SYNC,
+	FLAC__OGG_DECODER_ASPECT_READ_STATUS_NOT_FLAC,
+	FLAC__OGG_DECODER_ASPECT_READ_STATUS_UNSUPPORTED_MAPPING_VERSION,
+	FLAC__OGG_DECODER_ASPECT_READ_STATUS_ABORT,
+	FLAC__OGG_DECODER_ASPECT_READ_STATUS_ERROR,
+	FLAC__OGG_DECODER_ASPECT_READ_STATUS_MEMORY_ALLOCATION_ERROR
+} FLAC__OggDecoderAspectReadStatus;
+
+typedef FLAC__OggDecoderAspectReadStatus (*FLAC__OggDecoderAspectReadCallbackProxy)(const void *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data);
+
+FLAC__OggDecoderAspectReadStatus FLAC__ogg_decoder_aspect_read_callback_wrapper(FLAC__OggDecoderAspect *aspect, FLAC__byte buffer[], size_t *bytes, FLAC__OggDecoderAspectReadCallbackProxy read_callback, const FLAC__StreamDecoder *decoder, void *client_data);
+
+#endif
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/private/ogg_encoder_aspect.h
@@ -1,0 +1,63 @@
+/* libFLAC - Free Lossless Audio Codec
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2014  Xiph.Org Foundation
+ *
+ * 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__OGG_ENCODER_ASPECT_H
+#define FLAC__PRIVATE__OGG_ENCODER_ASPECT_H
+
+#include <ogg/ogg.h>
+
+#include "FLAC/ordinals.h"
+#include "FLAC/stream_encoder.h" /* for FLAC__StreamEncoderWriteStatus */
+
+typedef struct FLAC__OggEncoderAspect {
+	/* these are storage for values that can be set through the API */
+	long serial_number;
+	unsigned num_metadata;
+
+	/* these are for internal state related to Ogg encoding */
+	ogg_stream_state stream_state;
+	ogg_page page;
+	FLAC__bool seen_magic; /* true if we've seen the fLaC magic in the write callback yet */
+	FLAC__bool is_first_packet;
+	FLAC__uint64 samples_written;
+} FLAC__OggEncoderAspect;
+
+void FLAC__ogg_encoder_aspect_set_serial_number(FLAC__OggEncoderAspect *aspect, long value);
+FLAC__bool FLAC__ogg_encoder_aspect_set_num_metadata(FLAC__OggEncoderAspect *aspect, unsigned value);
+void FLAC__ogg_encoder_aspect_set_defaults(FLAC__OggEncoderAspect *aspect);
+FLAC__bool FLAC__ogg_encoder_aspect_init(FLAC__OggEncoderAspect *aspect);
+void FLAC__ogg_encoder_aspect_finish(FLAC__OggEncoderAspect *aspect);
+
+typedef FLAC__StreamEncoderWriteStatus (*FLAC__OggEncoderAspectWriteCallbackProxy)(const void *encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame, void *client_data);
+
+FLAC__StreamEncoderWriteStatus FLAC__ogg_encoder_aspect_write_callback_wrapper(FLAC__OggEncoderAspect *aspect, const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame, FLAC__bool is_last_block, FLAC__OggEncoderAspectWriteCallbackProxy write_callback, void *encoder, void *client_data);
+#endif
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/private/ogg_helper.h
@@ -1,0 +1,44 @@
+/* libFLAC - Free Lossless Audio Codec
+ * Copyright (C) 2004-2009  Josh Coalson
+ * Copyright (C) 2011-2014  Xiph.Org Foundation
+ *
+ * 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__OGG_HELPER_H
+#define FLAC__PRIVATE__OGG_HELPER_H
+
+#include <ogg/ogg.h>
+#include "FLAC/stream_encoder.h" /* for FLAC__StreamEncoder */
+
+void simple_ogg_page__init(ogg_page *page);
+void simple_ogg_page__clear(ogg_page *page);
+FLAC__bool simple_ogg_page__get_at(FLAC__StreamEncoder *encoder, FLAC__uint64 position, ogg_page *page, FLAC__StreamEncoderSeekCallback seek_callback, FLAC__StreamEncoderReadCallback read_callback, void *client_data);
+FLAC__bool simple_ogg_page__set_at(FLAC__StreamEncoder *encoder, FLAC__uint64 position, ogg_page *page, FLAC__StreamEncoderSeekCallback seek_callback, FLAC__StreamEncoderWriteCallback write_callback, void *client_data);
+
+#endif
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/private/ogg_mapping.h
@@ -1,0 +1,64 @@
+/* libFLAC - Free Lossless Audio Codec
+ * Copyright (C) 2004-2009  Josh Coalson
+ * Copyright (C) 2011-2014  Xiph.Org Foundation
+ *
+ * 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__OGG_MAPPING_H
+#define FLAC__PRIVATE__OGG_MAPPING_H
+
+#include "FLAC/ordinals.h"
+
+/** The length of the packet type field in bytes. */
+#define FLAC__OGG_MAPPING_PACKET_TYPE_LENGTH (1u)
+
+extern const unsigned FLAC__OGG_MAPPING_PACKET_TYPE_LEN; /* = 8 bits */
+
+extern const FLAC__byte FLAC__OGG_MAPPING_FIRST_HEADER_PACKET_TYPE; /* = 0x7f */
+
+/** The length of the 'FLAC' magic in bytes. */
+#define FLAC__OGG_MAPPING_MAGIC_LENGTH (4u)
+
+extern const FLAC__byte * const FLAC__OGG_MAPPING_MAGIC; /* = "FLAC" */
+
+extern const unsigned FLAC__OGG_MAPPING_VERSION_MAJOR_LEN; /* = 8 bits */
+extern const unsigned FLAC__OGG_MAPPING_VERSION_MINOR_LEN; /* = 8 bits */
+
+/** The length of the Ogg FLAC mapping major version number in bytes. */
+#define FLAC__OGG_MAPPING_VERSION_MAJOR_LENGTH (1u)
+
+/** The length of the Ogg FLAC mapping minor version number in bytes. */
+#define FLAC__OGG_MAPPING_VERSION_MINOR_LENGTH (1u)
+
+extern const unsigned FLAC__OGG_MAPPING_NUM_HEADERS_LEN; /* = 16 bits */
+
+/** The length of the #-of-header-packets number bytes. */
+#define FLAC__OGG_MAPPING_NUM_HEADERS_LENGTH (2u)
+
+#endif
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/private/stream_encoder.h
@@ -1,0 +1,67 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2014  Xiph.Org Foundation
+ *
+ * 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_H
+#define FLAC__PRIVATE__STREAM_ENCODER_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/*
+ * This is used to avoid overflow with unusual signals in 32-bit
+ * accumulator in the *precompute_partition_info_sums_* functions.
+ */
+#define FLAC__MAX_EXTRA_RESIDUAL_BPS 4
+
+#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && defined FLAC__HAS_X86INTRIN
+#include "private/cpu.h"
+#include "FLAC/format.h"
+
+#ifdef FLAC__SSE2_SUPPORTED
+extern void FLAC__precompute_partition_info_sums_intrin_sse2(const FLAC__int32 residual[], FLAC__uint64 abs_residual_partition_sums[],
+			unsigned residual_samples, unsigned predictor_order, unsigned min_partition_order, unsigned max_partition_order, unsigned bps);
+#endif
+
+#ifdef FLAC__SSSE3_SUPPORTED
+extern void FLAC__precompute_partition_info_sums_intrin_ssse3(const FLAC__int32 residual[], FLAC__uint64 abs_residual_partition_sums[],
+			unsigned residual_samples, unsigned predictor_order, unsigned min_partition_order, unsigned max_partition_order, unsigned bps);
+#endif
+
+#ifdef FLAC__AVX2_SUPPORTED
+extern void FLAC__precompute_partition_info_sums_intrin_avx2(const FLAC__int32 residual[], FLAC__uint64 abs_residual_partition_sums[],
+			unsigned residual_samples, unsigned predictor_order, unsigned min_partition_order, unsigned max_partition_order, unsigned bps);
+#endif
+
+#endif
+
+#endif
--- a/sys/src/cmd/audio/libFLAC/private/stream_encoder_framing.h
+++ b/sys/src/cmd/audio/libFLAC/private/stream_encoder_framing.h
@@ -1,5 +1,6 @@
 /* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2000,2001,2002,2003,2004  Josh Coalson
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2014  Xiph.Org Foundation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -33,13 +34,13 @@
 #define FLAC__PRIVATE__STREAM_ENCODER_FRAMING_H
 
 #include "FLAC/format.h"
-#include "bitbuffer.h"
+#include "bitwriter.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);
+FLAC__bool FLAC__add_metadata_block(const FLAC__StreamMetadata *metadata, FLAC__BitWriter *bw);
+FLAC__bool FLAC__frame_add_header(const FLAC__FrameHeader *header, FLAC__BitWriter *bw);
+FLAC__bool FLAC__subframe_add_constant(const FLAC__Subframe_Constant *subframe, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitWriter *bw);
+FLAC__bool FLAC__subframe_add_fixed(const FLAC__Subframe_Fixed *subframe, unsigned residual_samples, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitWriter *bw);
+FLAC__bool FLAC__subframe_add_lpc(const FLAC__Subframe_LPC *subframe, unsigned residual_samples, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitWriter *bw);
+FLAC__bool FLAC__subframe_add_verbatim(const FLAC__Subframe_Verbatim *subframe, unsigned samples, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitWriter *bw);
 
 #endif
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/private/window.h
@@ -1,0 +1,74 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2006-2009  Josh Coalson
+ * Copyright (C) 2011-2014  Xiph.Org Foundation
+ *
+ * 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__WINDOW_H
+#define FLAC__PRIVATE__WINDOW_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "private/float.h"
+#include "FLAC/format.h"
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+
+/*
+ *	FLAC__window_*()
+ *	--------------------------------------------------------------------
+ *	Calculates window coefficients according to different apodization
+ *	functions.
+ *
+ *	OUT window[0,L-1]
+ *	IN L (number of points in window)
+ */
+void FLAC__window_bartlett(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_bartlett_hann(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_blackman(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_blackman_harris_4term_92db_sidelobe(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_connes(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_flattop(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_gauss(FLAC__real *window, const FLAC__int32 L, const FLAC__real stddev); /* 0.0 < stddev <= 0.5 */
+void FLAC__window_hamming(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_hann(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_kaiser_bessel(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_nuttall(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_rectangle(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_triangle(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p);
+void FLAC__window_partial_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p, const FLAC__real start, const FLAC__real end);
+void FLAC__window_punchout_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p, const FLAC__real start, const FLAC__real end);
+void FLAC__window_welch(FLAC__real *window, const FLAC__int32 L);
+
+#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */
+
+#endif
--- a/sys/src/cmd/audio/libFLAC/protected/all.h
+++ b/sys/src/cmd/audio/libFLAC/protected/all.h
@@ -1,5 +1,6 @@
 /* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2001,2002,2003,2004  Josh Coalson
+ * Copyright (C) 2001-2009  Josh Coalson
+ * Copyright (C) 2011-2014  Xiph.Org Foundation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -32,10 +33,6 @@
 #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"
 
--- a/sys/src/cmd/audio/libFLAC/protected/file_decoder.h
+++ /dev/null
@@ -1,41 +1,0 @@
-/* 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
--- a/sys/src/cmd/audio/libFLAC/protected/file_encoder.h
+++ /dev/null
@@ -1,41 +1,0 @@
-/* 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
--- a/sys/src/cmd/audio/libFLAC/protected/seekable_stream_decoder.h
+++ /dev/null
@@ -1,42 +1,0 @@
-/* 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
--- a/sys/src/cmd/audio/libFLAC/protected/seekable_stream_encoder.h
+++ /dev/null
@@ -1,42 +1,0 @@
-/* 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
--- a/sys/src/cmd/audio/libFLAC/protected/stream_decoder.h
+++ b/sys/src/cmd/audio/libFLAC/protected/stream_decoder.h
@@ -1,5 +1,6 @@
 /* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2000,2001,2002,2003,2004  Josh Coalson
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2014  Xiph.Org Foundation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -33,14 +34,22 @@
 #define FLAC__PROTECTED__STREAM_DECODER_H
 
 #include "FLAC/stream_decoder.h"
+#if FLAC__HAS_OGG
+#include "private/ogg_decoder_aspect.h"
+#endif
 
 typedef struct FLAC__StreamDecoderProtected {
 	FLAC__StreamDecoderState state;
+	FLAC__StreamDecoderInitStatus initstate;
 	unsigned channels;
 	FLAC__ChannelAssignment channel_assignment;
 	unsigned bits_per_sample;
 	unsigned sample_rate; /* in Hz */
 	unsigned blocksize; /* in samples (per channel) */
+	FLAC__bool md5_checking; /* if true, generate MD5 signature of decoded data and compare against signature in the STREAMINFO metadata block */
+#if FLAC__HAS_OGG
+	FLAC__OggDecoderAspect ogg_decoder_aspect;
+#endif
 } FLAC__StreamDecoderProtected;
 
 /*
--- a/sys/src/cmd/audio/libFLAC/protected/stream_encoder.h
+++ b/sys/src/cmd/audio/libFLAC/protected/stream_encoder.h
@@ -1,5 +1,6 @@
 /* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2001,2002,2003,2004  Josh Coalson
+ * Copyright (C) 2001-2009  Josh Coalson
+ * Copyright (C) 2011-2014  Xiph.Org Foundation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -33,11 +34,60 @@
 #define FLAC__PROTECTED__STREAM_ENCODER_H
 
 #include "FLAC/stream_encoder.h"
+#if FLAC__HAS_OGG
+#include "private/ogg_encoder_aspect.h"
+#endif
 
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+
+#include "private/float.h"
+
+#define FLAC__MAX_APODIZATION_FUNCTIONS 32
+
+typedef enum {
+	FLAC__APODIZATION_BARTLETT,
+	FLAC__APODIZATION_BARTLETT_HANN,
+	FLAC__APODIZATION_BLACKMAN,
+	FLAC__APODIZATION_BLACKMAN_HARRIS_4TERM_92DB_SIDELOBE,
+	FLAC__APODIZATION_CONNES,
+	FLAC__APODIZATION_FLATTOP,
+	FLAC__APODIZATION_GAUSS,
+	FLAC__APODIZATION_HAMMING,
+	FLAC__APODIZATION_HANN,
+	FLAC__APODIZATION_KAISER_BESSEL,
+	FLAC__APODIZATION_NUTTALL,
+	FLAC__APODIZATION_RECTANGLE,
+	FLAC__APODIZATION_TRIANGLE,
+	FLAC__APODIZATION_TUKEY,
+	FLAC__APODIZATION_PARTIAL_TUKEY,
+	FLAC__APODIZATION_PUNCHOUT_TUKEY,
+	FLAC__APODIZATION_WELCH
+} FLAC__ApodizationFunction;
+
+typedef struct {
+	FLAC__ApodizationFunction type;
+	union {
+		struct {
+			FLAC__real stddev;
+		} gauss;
+		struct {
+			FLAC__real p;
+		} tukey;
+		struct {
+			FLAC__real p;
+			FLAC__real start;
+			FLAC__real end;
+		} multiple_tukey;
+	} parameters;
+} FLAC__ApodizationSpecification;
+
+#endif
+
 typedef struct FLAC__StreamEncoderProtected {
 	FLAC__StreamEncoderState state;
 	FLAC__bool verify;
 	FLAC__bool streamable_subset;
+	FLAC__bool do_md5;
 	FLAC__bool do_mid_side_stereo;
 	FLAC__bool loose_mid_side_stereo;
 	unsigned channels;
@@ -44,6 +94,10 @@
 	unsigned bits_per_sample;
 	unsigned sample_rate;
 	unsigned blocksize;
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+	unsigned num_apodizations;
+	FLAC__ApodizationSpecification apodizations[FLAC__MAX_APODIZATION_FUNCTIONS];
+#endif
 	unsigned max_lpc_order;
 	unsigned qlp_coeff_precision;
 	FLAC__bool do_qlp_coeff_prec_search;
@@ -55,6 +109,10 @@
 	FLAC__uint64 total_samples_estimate;
 	FLAC__StreamMetadata **metadata;
 	unsigned num_metadata_blocks;
+	FLAC__uint64 streaminfo_offset, seektable_offset, audio_offset;
+#if FLAC__HAS_OGG
+	FLAC__OggEncoderAspect ogg_encoder_aspect;
+#endif
 } FLAC__StreamEncoderProtected;
 
 #endif
--- a/sys/src/cmd/audio/libFLAC/seekable_stream_decoder.c
+++ /dev/null
@@ -1,1087 +1,0 @@
-/* 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(void)
-{
-	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;
-}
--- a/sys/src/cmd/audio/libFLAC/seekable_stream_encoder.c
+++ /dev/null
@@ -1,944 +1,0 @@
-/* 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"
-};
-
-FLAC_API FLAC__StreamEncoder *FLAC__stream_encoder_new(void);
-
-/***********************************************************************
- *
- * Class constructor/destructor
- *
- ***********************************************************************/
-
-FLAC_API FLAC__SeekableStreamEncoder *FLAC__seekable_stream_encoder_new(void)
-{
-	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/share/alloc.h
@@ -1,0 +1,209 @@
+/* alloc - Convenience routines for safely allocating memory
+ * Copyright (C) 2007-2009  Josh Coalson
+ * Copyright (C) 2011-2014  Xiph.Org Foundation
+ *
+ * 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__SHARE__ALLOC_H
+#define FLAC__SHARE__ALLOC_H
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+/* WATCHOUT: for c++ you may have to #define __STDC_LIMIT_MACROS 1 real early
+ * before #including this file,  otherwise SIZE_MAX might not be defined
+ */
+
+#include <limits.h> /* for SIZE_MAX */
+#if HAVE_STDINT_H
+#include <stdint.h> /* for SIZE_MAX in case limits.h didn't get it */
+#endif
+#include <stdlib.h> /* for size_t, malloc(), etc */
+#include "share/compat.h"
+
+#ifndef SIZE_MAX
+# ifndef SIZE_T_MAX
+#  ifdef _MSC_VER
+#   ifdef _WIN64
+#    define SIZE_T_MAX 0xffffffffffffffffui64
+#   else
+#    define SIZE_T_MAX 0xffffffff
+#   endif
+#  else
+#   error
+#  endif
+# endif
+# define SIZE_MAX SIZE_T_MAX
+#endif
+
+/* avoid malloc()ing 0 bytes, see:
+ * https://www.securecoding.cert.org/confluence/display/seccode/MEM04-A.+Do+not+make+assumptions+about+the+result+of+allocating+0+bytes?focusedCommentId=5407003
+*/
+static inline void *safe_malloc_(size_t size)
+{
+	/* malloc(0) is undefined; FLAC src convention is to always allocate */
+	if(!size)
+		size++;
+	return malloc(size);
+}
+
+static inline void *safe_calloc_(size_t nmemb, size_t size)
+{
+	if(!nmemb || !size)
+		return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */
+	return calloc(nmemb, size);
+}
+
+/*@@@@ there's probably a better way to prevent overflows when allocating untrusted sums but this works for now */
+
+static inline void *safe_malloc_add_2op_(size_t size1, size_t size2)
+{
+	size2 += size1;
+	if(size2 < size1)
+		return 0;
+	return safe_malloc_(size2);
+}
+
+static inline void *safe_malloc_add_3op_(size_t size1, size_t size2, size_t size3)
+{
+	size2 += size1;
+	if(size2 < size1)
+		return 0;
+	size3 += size2;
+	if(size3 < size2)
+		return 0;
+	return safe_malloc_(size3);
+}
+
+static inline void *safe_malloc_add_4op_(size_t size1, size_t size2, size_t size3, size_t size4)
+{
+	size2 += size1;
+	if(size2 < size1)
+		return 0;
+	size3 += size2;
+	if(size3 < size2)
+		return 0;
+	size4 += size3;
+	if(size4 < size3)
+		return 0;
+	return safe_malloc_(size4);
+}
+
+void *safe_malloc_mul_2op_(size_t size1, size_t size2) ;
+
+static inline void *safe_malloc_mul_3op_(size_t size1, size_t size2, size_t size3)
+{
+	if(!size1 || !size2 || !size3)
+		return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */
+	if(size1 > SIZE_MAX / size2)
+		return 0;
+	size1 *= size2;
+	if(size1 > SIZE_MAX / size3)
+		return 0;
+	return malloc(size1*size3);
+}
+
+/* size1*size2 + size3 */
+static inline void *safe_malloc_mul2add_(size_t size1, size_t size2, size_t size3)
+{
+	if(!size1 || !size2)
+		return safe_malloc_(size3);
+	if(size1 > SIZE_MAX / size2)
+		return 0;
+	return safe_malloc_add_2op_(size1*size2, size3);
+}
+
+/* size1 * (size2 + size3) */
+static inline void *safe_malloc_muladd2_(size_t size1, size_t size2, size_t size3)
+{
+	if(!size1 || (!size2 && !size3))
+		return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */
+	size2 += size3;
+	if(size2 < size3)
+		return 0;
+	if(size1 > SIZE_MAX / size2)
+		return 0;
+	return malloc(size1*size2);
+}
+
+static inline void *safe_realloc_add_2op_(void *ptr, size_t size1, size_t size2)
+{
+	size2 += size1;
+	if(size2 < size1)
+		return 0;
+	return realloc(ptr, size2);
+}
+
+static inline void *safe_realloc_add_3op_(void *ptr, size_t size1, size_t size2, size_t size3)
+{
+	size2 += size1;
+	if(size2 < size1)
+		return 0;
+	size3 += size2;
+	if(size3 < size2)
+		return 0;
+	return realloc(ptr, size3);
+}
+
+static inline void *safe_realloc_add_4op_(void *ptr, size_t size1, size_t size2, size_t size3, size_t size4)
+{
+	size2 += size1;
+	if(size2 < size1)
+		return 0;
+	size3 += size2;
+	if(size3 < size2)
+		return 0;
+	size4 += size3;
+	if(size4 < size3)
+		return 0;
+	return realloc(ptr, size4);
+}
+
+static inline void *safe_realloc_mul_2op_(void *ptr, size_t size1, size_t size2)
+{
+	if(!size1 || !size2)
+		return realloc(ptr, 0); /* preserve POSIX realloc(ptr, 0) semantics */
+	if(size1 > SIZE_MAX / size2)
+		return 0;
+	return realloc(ptr, size1*size2);
+}
+
+/* size1 * (size2 + size3) */
+static inline void *safe_realloc_muladd2_(void *ptr, size_t size1, size_t size2, size_t size3)
+{
+	if(!size1 || (!size2 && !size3))
+		return realloc(ptr, 0); /* preserve POSIX realloc(ptr, 0) semantics */
+	size2 += size3;
+	if(size2 < size3)
+		return 0;
+	return safe_realloc_mul_2op_(ptr, size1, size2);
+}
+
+#endif
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/share/compat.h
@@ -1,0 +1,201 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2012-2014  Xiph.org Foundation
+ *
+ * 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.
+ */
+
+/* This is the prefered location of all CPP hackery to make $random_compiler
+ * work like something approaching a C99 (or maybe more accurately GNU99)
+ * compiler.
+ *
+ * It is assumed that this header will be included after "config.h".
+ */
+
+#ifndef FLAC__SHARE__COMPAT_H
+#define FLAC__SHARE__COMPAT_H
+
+#if defined _WIN32 && !defined __CYGWIN__
+/* where MSVC puts unlink() */
+# include <io.h>
+#else
+# include <unistd.h>
+#endif
+
+#if defined _MSC_VER || defined __BORLANDC__ || defined __MINGW32__
+#include <sys/types.h> /* for off_t */
+#define FLAC__off_t __int64 /* use this instead of off_t to fix the 2 GB limit */
+#if !defined __MINGW32__
+#define fseeko _fseeki64
+#define ftello _ftelli64
+#else /* MinGW */
+#if !defined(HAVE_FSEEKO)
+#define fseeko fseeko64
+#define ftello ftello64
+#endif
+#endif
+#else
+#define FLAC__off_t off_t
+#endif
+
+#if HAVE_INTTYPES_H
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+#endif
+
+#if defined(_MSC_VER)
+#define strtoll _strtoi64
+#define strtoull _strtoui64
+#endif
+
+#if defined(_MSC_VER)
+#define inline __inline
+#endif
+
+#if defined __INTEL_COMPILER || (defined _MSC_VER && defined _WIN64)
+/* MSVS generates VERY slow 32-bit code with __restrict */
+#define flac_restrict __restrict
+#elif defined __GNUC__
+#define flac_restrict __restrict__
+#else
+#define flac_restrict
+#endif
+
+#define FLAC__U64L(x) x##ULL
+
+#if defined _MSC_VER || defined __BORLANDC__ || defined __MINGW32__
+#define FLAC__STRCASECMP stricmp
+#define FLAC__STRNCASECMP strnicmp
+#else
+#define FLAC__STRCASECMP strcasecmp
+#define FLAC__STRNCASECMP strncasecmp
+#endif
+
+#if defined _MSC_VER || defined __MINGW32__ || defined __CYGWIN__ || defined __EMX__
+#include <io.h> /* for _setmode(), chmod() */
+#include <fcntl.h> /* for _O_BINARY */
+#else
+#include <unistd.h> /* for chown(), unlink() */
+#endif
+
+#if defined _MSC_VER || defined __BORLANDC__ || defined __MINGW32__
+#if defined __BORLANDC__
+#include <utime.h> /* for utime() */
+#else
+#include <sys/utime.h> /* for utime() */
+#endif
+#else
+#include <sys/types.h> /* some flavors of BSD (like OS X) require this to get time_t */
+#include <utime.h> /* for utime() */
+#endif
+
+#if defined _MSC_VER
+#  if _MSC_VER >= 1600
+/* Visual Studio 2010 has decent C99 support */
+#    include <stdint.h>
+#    define PRIu64 "llu"
+#    define PRId64 "lld"
+#    define PRIx64 "llx"
+#  else
+#    include <limits.h>
+#    ifndef UINT32_MAX
+#      define UINT32_MAX _UI32_MAX
+#    endif
+     typedef unsigned __int64 uint64_t;
+     typedef unsigned __int32 uint32_t;
+     typedef unsigned __int16 uint16_t;
+     typedef unsigned __int8 uint8_t;
+     typedef __int64 int64_t;
+     typedef __int32 int32_t;
+     typedef __int16 int16_t;
+     typedef __int8  int8_t;
+#    define PRIu64 "I64u"
+#    define PRId64 "I64d"
+#    define PRIx64 "I64x"
+#  endif
+#endif /* defined _MSC_VER */
+
+#ifdef _WIN32
+/* All char* strings are in UTF-8 format. Added to support Unicode files on Windows */
+#include "share/win_utf8_io.h"
+
+#define flac_printf printf_utf8
+#define flac_fprintf fprintf_utf8
+#define flac_vfprintf vfprintf_utf8
+#define flac_fopen fopen_utf8
+#define flac_chmod chmod_utf8
+#define flac_utime utime_utf8
+#define flac_unlink unlink_utf8
+#define flac_rename rename_utf8
+#define flac_stat _stat64_utf8
+
+#else
+
+#define flac_printf printf
+#define flac_fprintf fprintf
+#define flac_vfprintf vfprintf
+#define flac_fopen fopen
+#define flac_chmod chmod
+#define flac_utime utime
+#define flac_unlink unlink
+#define flac_rename rename
+#define flac_stat stat
+
+#endif
+
+#ifdef _WIN32
+#define flac_stat_s __stat64 /* stat struct */
+#define flac_fstat _fstat64
+#else
+#define flac_stat_s stat /* stat struct */
+#define flac_fstat fstat
+#endif
+
+#ifndef M_LN2
+#define M_LN2 0.69314718055994530942
+#endif
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+/* FLAC needs to compile and work correctly on systems with a normal ISO C99
+ * snprintf as well as Microsoft Visual Studio which has an non-standards
+ * conformant snprint_s function.
+ *
+ * This function wraps the MS version to behave more like the the ISO version.
+ */
+#include <stdarg.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+int flac_snprintf(char *str, size_t size, const char *fmt, ...);
+int flac_vsnprintf(char *str, size_t size, const char *fmt, va_list va);
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* FLAC__SHARE__COMPAT_H */
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/share/endswap.h
@@ -1,0 +1,78 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2012-2014  Xiph.org Foundation
+ *
+ * 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.
+ */
+
+/* It is assumed that this header will be included after "config.h". */
+
+#if HAVE_BSWAP32			/* GCC and Clang */
+
+/* GCC prior to 4.8 didn't provide bswap16 on x86_64 */
+#if ! HAVE_BSWAP16
+static inline unsigned short __builtin_bswap16(unsigned short a)
+{
+	return (a<<8)|(a>>8);
+}
+#endif
+
+#define	ENDSWAP_16(x)		(__builtin_bswap16 (x))
+#define	ENDSWAP_32(x)		(__builtin_bswap32 (x))
+
+#elif defined _MSC_VER		/* Windows. Apparently in <stdlib.h>. */
+
+#define	ENDSWAP_16(x)		(_byteswap_ushort (x))
+#define	ENDSWAP_32(x)		(_byteswap_ulong (x))
+
+#elif defined HAVE_BYTESWAP_H		/* Linux */
+
+#include <byteswap.h>
+
+#define	ENDSWAP_16(x)		(bswap_16 (x))
+#define	ENDSWAP_32(x)		(bswap_32 (x))
+
+#else
+
+#define	ENDSWAP_16(x)		((((x) >> 8) & 0xFF) | (((x) & 0xFF) << 8))
+#define	ENDSWAP_32(x)		((((x) >> 24) & 0xFF) | (((x) >> 8) & 0xFF00) | (((x) & 0xFF00) << 8) | (((x) & 0xFF) << 24))
+
+#endif
+
+
+/* Host to little-endian byte swapping. */
+#if CPU_IS_BIG_ENDIAN
+
+#define H2LE_16(x)		ENDSWAP_16 (x)
+#define H2LE_32(x)		ENDSWAP_32 (x)
+
+#else
+
+#define H2LE_16(x)		(x)
+#define H2LE_32(x)		(x)
+
+#endif
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/share/macros.h
@@ -1,0 +1,41 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2013-2014  Xiph.org Foundation
+ *
+ * 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>
+
+/* FLAC_CHECK_RETURN : Check the return value of of the provided function and
+ * print and error message if it fails (ie returns a value < 0).
+ */
+
+#define FLAC_CHECK_RETURN(x) \
+			{	if ((x) < 0) \
+					printf ("%s : %s\n", #x, strerror (errno)) ; \
+			}
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/share/private.h
@@ -1,0 +1,45 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2013-2014  Xiph.org Foundation
+ *
+ * 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__SHARE__PRIVATE_H
+#define FLAC__SHARE__PRIVATE_H
+
+/*
+ * Unpublished debug routines from libFLAC> This should not be used from any
+ * client code other than code shipped with the FLAC sources.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_disable_constant_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value);
+FLAC_API FLAC__bool FLAC__stream_encoder_disable_fixed_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value);
+FLAC_API FLAC__bool FLAC__stream_encoder_disable_verbatim_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value);
+FLAC_API FLAC__bool FLAC__stream_encoder_set_do_md5(FLAC__StreamEncoder *encoder, FLAC__bool value);
+FLAC_API FLAC__bool FLAC__stream_encoder_get_do_md5(const FLAC__StreamEncoder *encoder);
+
+#endif /* FLAC__SHARE__PRIVATE_H */
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/share/safe_str.h
@@ -1,0 +1,69 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2013-2014  Xiph.org Foundation
+ *
+ * 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.
+ */
+
+/* Safe string handling functions to replace things like strcpy, strncpy,
+ * strcat, strncat etc.
+ * All of these functions guarantee a correctly NUL terminated string but
+ * the string may be truncated if the destination buffer was too short.
+ */
+
+#ifndef FLAC__SHARE_SAFE_STR_H
+#define FLAC__SHARE_SAFE_STR_H
+
+static inline char *
+safe_strncat(char *dest, const char *src, size_t dest_size)
+{
+	char * ret;
+
+	if (dest_size < 1)
+		return dest;
+
+	ret = strncat(dest, src, dest_size - strlen (dest));
+	dest [dest_size - 1] = 0;
+
+	return ret;
+}
+
+static inline char *
+safe_strncpy(char *dest, const char *src, size_t dest_size)
+{
+	char * ret;
+
+	if (dest_size < 1)
+		return dest;
+
+	ret = strncpy(dest, src, dest_size);
+	dest [dest_size - 1] = 0;
+
+	return ret;
+}
+
+#endif /* FLAC__SHARE_SAFE_STR_H */
--- a/sys/src/cmd/audio/libFLAC/stream_decoder.c
+++ b/sys/src/cmd/audio/libFLAC/stream_decoder.c
@@ -1,5 +1,6 @@
 /* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2000,2001,2002,2003,2004  Josh Coalson
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2014  Xiph.Org Foundation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -29,12 +30,20 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
 #include <stdio.h>
 #include <stdlib.h> /* for malloc() */
 #include <string.h> /* for memset/memcpy() */
+#include <sys/stat.h> /* for stat() */
+#include <sys/types.h> /* for off_t */
+#include "share/compat.h"
 #include "FLAC/assert.h"
+#include "share/alloc.h"
 #include "protected/stream_decoder.h"
-#include "private/bitbuffer.h"
+#include "private/bitreader.h"
 #include "private/bitmath.h"
 #include "private/cpu.h"
 #include "private/crc.h"
@@ -41,24 +50,21 @@
 #include "private/fixed.h"
 #include "private/format.h"
 #include "private/lpc.h"
+#include "private/md5.h"
 #include "private/memory.h"
+#include "private/macros.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
+/* technically this should be in an "export.c" but this is convenient enough */
+FLAC_API int FLAC_API_SUPPORTS_OGG_FLAC =
+#if FLAC__HAS_OGG
+	1
 #else
-#define FLAC__U64L(x) x##LLU
+	0
 #endif
+;
 
+
 /***********************************************************************
  *
  * Private static data
@@ -65,7 +71,7 @@
  *
  ***********************************************************************/
 
-static FLAC__byte ID3V2_TAG_[3] = { 'I', 'D', '3' };
+static const FLAC__byte ID3V2_TAG_[3] = { 'I', 'D', '3' };
 
 /***********************************************************************
  *
@@ -74,6 +80,7 @@
  ***********************************************************************/
 
 static void set_defaults_(FLAC__StreamDecoder *decoder);
+static FILE *get_binary_stdin_(void);
 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);
@@ -80,8 +87,9 @@
 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_vorbiscomment_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_VorbisComment *obj, unsigned length);
 static FLAC__bool read_metadata_cuesheet_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_CueSheet *obj);
+static FLAC__bool read_metadata_picture_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_Picture *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);
@@ -91,9 +99,24 @@
 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_residual_partitioned_rice_(FLAC__StreamDecoder *decoder, unsigned predictor_order, unsigned partition_order, FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents, FLAC__int32 *residual, FLAC__bool is_extended);
 static FLAC__bool read_zero_padding_(FLAC__StreamDecoder *decoder);
-static FLAC__bool read_callback_(FLAC__byte buffer[], unsigned *bytes, void *client_data);
+static FLAC__bool read_callback_(FLAC__byte buffer[], size_t *bytes, void *client_data);
+#if FLAC__HAS_OGG
+static FLAC__StreamDecoderReadStatus read_callback_ogg_aspect_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes);
+static FLAC__OggDecoderAspectReadStatus read_callback_proxy_(const void *void_decoder, FLAC__byte buffer[], size_t *bytes, void *client_data);
+#endif
+static FLAC__StreamDecoderWriteStatus write_audio_frame_to_client_(FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[]);
+static void send_error_to_client_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status);
+static FLAC__bool seek_to_absolute_sample_(FLAC__StreamDecoder *decoder, FLAC__uint64 stream_length, FLAC__uint64 target_sample);
+#if FLAC__HAS_OGG
+static FLAC__bool seek_to_absolute_sample_ogg_(FLAC__StreamDecoder *decoder, FLAC__uint64 stream_length, FLAC__uint64 target_sample);
+#endif
+static FLAC__StreamDecoderReadStatus file_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data);
+static FLAC__StreamDecoderSeekStatus file_seek_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data);
+static FLAC__StreamDecoderTellStatus file_tell_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data);
+static FLAC__StreamDecoderLengthStatus file_length_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data);
+static FLAC__bool file_eof_callback_(const FLAC__StreamDecoder *decoder, void *client_data);
 
 /***********************************************************************
  *
@@ -102,7 +125,14 @@
  ***********************************************************************/
 
 typedef struct FLAC__StreamDecoderPrivate {
+#if FLAC__HAS_OGG
+	FLAC__bool is_ogg;
+#endif
 	FLAC__StreamDecoderReadCallback read_callback;
+	FLAC__StreamDecoderSeekCallback seek_callback;
+	FLAC__StreamDecoderTellCallback tell_callback;
+	FLAC__StreamDecoderLengthCallback length_callback;
+	FLAC__StreamDecoderEofCallback eof_callback;
 	FLAC__StreamDecoderWriteCallback write_callback;
 	FLAC__StreamDecoderMetadataCallback metadata_callback;
 	FLAC__StreamDecoderErrorCallback error_callback;
@@ -112,15 +142,14 @@
 	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;
+	FILE *file; /* only used if FLAC__stream_decoder_init_file()/FLAC__stream_decoder_init_file() called, else NULL */
+	FLAC__BitReader *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__uint32 fixed_block_size, next_fixed_block_size;
 	FLAC__uint64 samples_decoded;
 	FLAC__bool has_stream_info, has_seek_table;
 	FLAC__StreamMetadata stream_info;
@@ -127,7 +156,7 @@
 	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 */
+	size_t 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;
@@ -135,6 +164,19 @@
 	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__bool do_md5_checking; /* initially gets protected_->md5_checking but is turned off after a seek or if the metadata has a zero MD5 */
+	FLAC__bool internal_reset_hack; /* used only during init() so we can call reset to set up the decoder without rewinding the input */
+	FLAC__bool is_seeking;
+	FLAC__MD5Context md5context;
+	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__Frame last_frame; /* holds the info of the last frame we seeked to */
+	FLAC__uint64 first_frame_offset; /* hint to the seek routine of where in the stream the first audio frame starts */
+	FLAC__uint64 target_sample;
+	unsigned unparseable_frame_count; /* used to tell whether we're decoding a future version of FLAC or just got a bad sync */
+#if FLAC__HAS_OGG
+	FLAC__bool got_a_frame; /* hack needed in Ogg FLAC seek routine to check when process_single() actually writes a frame */
+#endif
 } FLAC__StreamDecoderPrivate;
 
 /***********************************************************************
@@ -149,14 +191,22 @@
 	"FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC",
 	"FLAC__STREAM_DECODER_READ_FRAME",
 	"FLAC__STREAM_DECODER_END_OF_STREAM",
+	"FLAC__STREAM_DECODER_OGG_ERROR",
+	"FLAC__STREAM_DECODER_SEEK_ERROR",
 	"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__StreamDecoderInitStatusString[] = {
+	"FLAC__STREAM_DECODER_INIT_STATUS_OK",
+	"FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER",
+	"FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS",
+	"FLAC__STREAM_DECODER_INIT_STATUS_MEMORY_ALLOCATION_ERROR",
+	"FLAC__STREAM_DECODER_INIT_STATUS_ERROR_OPENING_FILE",
+	"FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED"
+};
+
 FLAC_API const char * const FLAC__StreamDecoderReadStatusString[] = {
 	"FLAC__STREAM_DECODER_READ_STATUS_CONTINUE",
 	"FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM",
@@ -163,6 +213,24 @@
 	"FLAC__STREAM_DECODER_READ_STATUS_ABORT"
 };
 
+FLAC_API const char * const FLAC__StreamDecoderSeekStatusString[] = {
+	"FLAC__STREAM_DECODER_SEEK_STATUS_OK",
+	"FLAC__STREAM_DECODER_SEEK_STATUS_ERROR",
+	"FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED"
+};
+
+FLAC_API const char * const FLAC__StreamDecoderTellStatusString[] = {
+	"FLAC__STREAM_DECODER_TELL_STATUS_OK",
+	"FLAC__STREAM_DECODER_TELL_STATUS_ERROR",
+	"FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED"
+};
+
+FLAC_API const char * const FLAC__StreamDecoderLengthStatusString[] = {
+	"FLAC__STREAM_DECODER_LENGTH_STATUS_OK",
+	"FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR",
+	"FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED"
+};
+
 FLAC_API const char * const FLAC__StreamDecoderWriteStatusString[] = {
 	"FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE",
 	"FLAC__STREAM_DECODER_WRITE_STATUS_ABORT"
@@ -171,17 +239,16 @@
 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"
+	"FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH",
+	"FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM"
 };
 
-FLAC__BitBuffer *FLAC__bitbuffer_new(void);
-
 /***********************************************************************
  *
  * Class constructor/destructor
  *
  ***********************************************************************/
-FLAC_API FLAC__StreamDecoder *FLAC__stream_decoder_new()
+FLAC_API FLAC__StreamDecoder *FLAC__stream_decoder_new(void)
 {
 	FLAC__StreamDecoder *decoder;
 	unsigned i;
@@ -188,18 +255,18 @@
 
 	FLAC__ASSERT(sizeof(int) >= 4); /* we want to die right away if this is not true */
 
-	decoder = (FLAC__StreamDecoder*)calloc(1, sizeof(FLAC__StreamDecoder));
+	decoder = calloc(1, sizeof(FLAC__StreamDecoder));
 	if(decoder == 0) {
 		return 0;
 	}
 
-	decoder->protected_ = (FLAC__StreamDecoderProtected*)calloc(1, sizeof(FLAC__StreamDecoderProtected));
+	decoder->protected_ = calloc(1, sizeof(FLAC__StreamDecoderProtected));
 	if(decoder->protected_ == 0) {
 		free(decoder);
 		return 0;
 	}
 
-	decoder->private_ = (FLAC__StreamDecoderPrivate*)calloc(1, sizeof(FLAC__StreamDecoderPrivate));
+	decoder->private_ = calloc(1, sizeof(FLAC__StreamDecoderPrivate));
 	if(decoder->private_ == 0) {
 		free(decoder->protected_);
 		free(decoder);
@@ -206,7 +273,7 @@
 		return 0;
 	}
 
-	decoder->private_->input = FLAC__bitbuffer_new();
+	decoder->private_->input = FLAC__bitreader_new();
 	if(decoder->private_->input == 0) {
 		free(decoder->private_);
 		free(decoder->protected_);
@@ -215,8 +282,8 @@
 	}
 
 	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);
+	if(0 == (decoder->private_->metadata_filter_ids = malloc((FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) * decoder->private_->metadata_filter_ids_capacity))) {
+		FLAC__bitreader_delete(decoder->private_->input);
 		free(decoder->private_);
 		free(decoder->protected_);
 		free(decoder);
@@ -235,6 +302,8 @@
 	for(i = 0; i < FLAC__MAX_CHANNELS; i++)
 		FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&decoder->private_->partitioned_rice_contents[i]);
 
+	decoder->private_->file = 0;
+
 	set_defaults_(decoder);
 
 	decoder->protected_->state = FLAC__STREAM_DECODER_UNINITIALIZED;
@@ -246,17 +315,19 @@
 {
 	unsigned i;
 
-	FLAC__ASSERT(0 != decoder);
+	if (decoder == NULL)
+		return ;
+
 	FLAC__ASSERT(0 != decoder->protected_);
 	FLAC__ASSERT(0 != decoder->private_);
 	FLAC__ASSERT(0 != decoder->private_->input);
 
-	FLAC__stream_decoder_finish(decoder);
+	(void)FLAC__stream_decoder_finish(decoder);
 
 	if(0 != decoder->private_->metadata_filter_ids)
 		free(decoder->private_->metadata_filter_ids);
 
-	FLAC__bitbuffer_delete(decoder->private_->input);
+	FLAC__bitreader_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]);
@@ -272,23 +343,43 @@
  *
  ***********************************************************************/
 
-FLAC_API FLAC__StreamDecoderState FLAC__stream_decoder_init(FLAC__StreamDecoder *decoder)
+static FLAC__StreamDecoderInitStatus init_stream_internal_(
+	FLAC__StreamDecoder *decoder,
+	FLAC__StreamDecoderReadCallback read_callback,
+	FLAC__StreamDecoderSeekCallback seek_callback,
+	FLAC__StreamDecoderTellCallback tell_callback,
+	FLAC__StreamDecoderLengthCallback length_callback,
+	FLAC__StreamDecoderEofCallback eof_callback,
+	FLAC__StreamDecoderWriteCallback write_callback,
+	FLAC__StreamDecoderMetadataCallback metadata_callback,
+	FLAC__StreamDecoderErrorCallback error_callback,
+	void *client_data,
+	FLAC__bool is_ogg
+)
 {
 	FLAC__ASSERT(0 != decoder);
 
 	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
-		return decoder->protected_->state = FLAC__STREAM_DECODER_ALREADY_INITIALIZED;
+		return FLAC__STREAM_DECODER_INIT_STATUS_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__HAS_OGG
+	if(is_ogg)
+		return FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER;
+#endif
 
-	if(!FLAC__bitbuffer_init(decoder->private_->input))
-		return decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+	if(
+		0 == read_callback ||
+		0 == write_callback ||
+		0 == error_callback ||
+		(seek_callback && (0 == tell_callback || 0 == length_callback || 0 == eof_callback))
+	)
+		return FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS;
 
-	decoder->private_->last_frame_number = 0;
-	decoder->private_->samples_decoded = 0;
-	decoder->private_->has_stream_info = false;
-	decoder->private_->cached = false;
+#if FLAC__HAS_OGG
+	decoder->private_->is_ogg = is_ogg;
+	if(is_ogg && !FLAC__ogg_decoder_aspect_init(&decoder->protected_->ogg_decoder_aspect))
+		return decoder->protected_->initstate = FLAC__STREAM_DECODER_INIT_STATUS_ERROR_OPENING_FILE;
+#endif
 
 	/*
 	 * get the CPU info and set the function pointers
@@ -298,7 +389,6 @@
 	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) {
@@ -305,45 +395,272 @@
 #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_64bit = FLAC__lpc_restore_signal_wide_asm_ia32; /* OPT_IA32: was really necessary for GCC < 4.9 */
+		if(decoder->private_->cpuinfo.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;
+#ifdef FLAC__HAS_X86INTRIN
+# if defined FLAC__SSE2_SUPPORTED && !defined FLAC__HAS_NASM /* OPT_SSE: not better than MMX asm */
+		if(decoder->private_->cpuinfo.ia32.sse2) {
+			decoder->private_->local_lpc_restore_signal_16bit = FLAC__lpc_restore_signal_16_intrin_sse2;
 		}
+# endif
+# if defined FLAC__SSE4_1_SUPPORTED
+		if(decoder->private_->cpuinfo.ia32.sse41) {
+			decoder->private_->local_lpc_restore_signal_64bit = FLAC__lpc_restore_signal_wide_intrin_sse41;
+		}
+# endif
 #endif
+#elif defined FLAC__CPU_X86_64
+		FLAC__ASSERT(decoder->private_->cpuinfo.type == FLAC__CPUINFO_TYPE_X86_64);
+		/* No useful SSE optimizations yet */
+#endif
 	}
 #endif
 
-	if(!FLAC__stream_decoder_reset(decoder))
-		return decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+	/* from here on, errors are fatal */
 
-	return decoder->protected_->state;
+	if(!FLAC__bitreader_init(decoder->private_->input, read_callback_, decoder)) {
+		decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+		return FLAC__STREAM_DECODER_INIT_STATUS_MEMORY_ALLOCATION_ERROR;
+	}
+
+	decoder->private_->read_callback = read_callback;
+	decoder->private_->seek_callback = seek_callback;
+	decoder->private_->tell_callback = tell_callback;
+	decoder->private_->length_callback = length_callback;
+	decoder->private_->eof_callback = eof_callback;
+	decoder->private_->write_callback = write_callback;
+	decoder->private_->metadata_callback = metadata_callback;
+	decoder->private_->error_callback = error_callback;
+	decoder->private_->client_data = client_data;
+	decoder->private_->fixed_block_size = decoder->private_->next_fixed_block_size = 0;
+	decoder->private_->samples_decoded = 0;
+	decoder->private_->has_stream_info = false;
+	decoder->private_->cached = false;
+
+	decoder->private_->do_md5_checking = decoder->protected_->md5_checking;
+	decoder->private_->is_seeking = false;
+
+	decoder->private_->internal_reset_hack = true; /* so the following reset does not try to rewind the input */
+	if(!FLAC__stream_decoder_reset(decoder)) {
+		/* above call sets the state for us */
+		return FLAC__STREAM_DECODER_INIT_STATUS_MEMORY_ALLOCATION_ERROR;
+	}
+
+	return FLAC__STREAM_DECODER_INIT_STATUS_OK;
 }
 
-FLAC_API void FLAC__stream_decoder_finish(FLAC__StreamDecoder *decoder)
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_stream(
+	FLAC__StreamDecoder *decoder,
+	FLAC__StreamDecoderReadCallback read_callback,
+	FLAC__StreamDecoderSeekCallback seek_callback,
+	FLAC__StreamDecoderTellCallback tell_callback,
+	FLAC__StreamDecoderLengthCallback length_callback,
+	FLAC__StreamDecoderEofCallback eof_callback,
+	FLAC__StreamDecoderWriteCallback write_callback,
+	FLAC__StreamDecoderMetadataCallback metadata_callback,
+	FLAC__StreamDecoderErrorCallback error_callback,
+	void *client_data
+)
 {
+	return init_stream_internal_(
+		decoder,
+		read_callback,
+		seek_callback,
+		tell_callback,
+		length_callback,
+		eof_callback,
+		write_callback,
+		metadata_callback,
+		error_callback,
+		client_data,
+		/*is_ogg=*/false
+	);
+}
+
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_stream(
+	FLAC__StreamDecoder *decoder,
+	FLAC__StreamDecoderReadCallback read_callback,
+	FLAC__StreamDecoderSeekCallback seek_callback,
+	FLAC__StreamDecoderTellCallback tell_callback,
+	FLAC__StreamDecoderLengthCallback length_callback,
+	FLAC__StreamDecoderEofCallback eof_callback,
+	FLAC__StreamDecoderWriteCallback write_callback,
+	FLAC__StreamDecoderMetadataCallback metadata_callback,
+	FLAC__StreamDecoderErrorCallback error_callback,
+	void *client_data
+)
+{
+	return init_stream_internal_(
+		decoder,
+		read_callback,
+		seek_callback,
+		tell_callback,
+		length_callback,
+		eof_callback,
+		write_callback,
+		metadata_callback,
+		error_callback,
+		client_data,
+		/*is_ogg=*/true
+	);
+}
+
+static FLAC__StreamDecoderInitStatus init_FILE_internal_(
+	FLAC__StreamDecoder *decoder,
+	FILE *file,
+	FLAC__StreamDecoderWriteCallback write_callback,
+	FLAC__StreamDecoderMetadataCallback metadata_callback,
+	FLAC__StreamDecoderErrorCallback error_callback,
+	void *client_data,
+	FLAC__bool is_ogg
+)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != file);
+
+	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+		return decoder->protected_->initstate = FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED;
+
+	if(0 == write_callback || 0 == error_callback)
+		return decoder->protected_->initstate = FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS;
+
+	/*
+	 * To make sure that our file does not go unclosed after an error, we
+	 * must assign the FILE pointer before any further error can occur in
+	 * this routine.
+	 */
+	if(file == stdin)
+		file = get_binary_stdin_(); /* just to be safe */
+
+	decoder->private_->file = file;
+
+	return init_stream_internal_(
+		decoder,
+		file_read_callback_,
+		decoder->private_->file == stdin? 0: file_seek_callback_,
+		decoder->private_->file == stdin? 0: file_tell_callback_,
+		decoder->private_->file == stdin? 0: file_length_callback_,
+		file_eof_callback_,
+		write_callback,
+		metadata_callback,
+		error_callback,
+		client_data,
+		is_ogg
+	);
+}
+
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_FILE(
+	FLAC__StreamDecoder *decoder,
+	FILE *file,
+	FLAC__StreamDecoderWriteCallback write_callback,
+	FLAC__StreamDecoderMetadataCallback metadata_callback,
+	FLAC__StreamDecoderErrorCallback error_callback,
+	void *client_data
+)
+{
+	return init_FILE_internal_(decoder, file, write_callback, metadata_callback, error_callback, client_data, /*is_ogg=*/false);
+}
+
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_FILE(
+	FLAC__StreamDecoder *decoder,
+	FILE *file,
+	FLAC__StreamDecoderWriteCallback write_callback,
+	FLAC__StreamDecoderMetadataCallback metadata_callback,
+	FLAC__StreamDecoderErrorCallback error_callback,
+	void *client_data
+)
+{
+	return init_FILE_internal_(decoder, file, write_callback, metadata_callback, error_callback, client_data, /*is_ogg=*/true);
+}
+
+static FLAC__StreamDecoderInitStatus init_file_internal_(
+	FLAC__StreamDecoder *decoder,
+	const char *filename,
+	FLAC__StreamDecoderWriteCallback write_callback,
+	FLAC__StreamDecoderMetadataCallback metadata_callback,
+	FLAC__StreamDecoderErrorCallback error_callback,
+	void *client_data,
+	FLAC__bool is_ogg
+)
+{
+	FILE *file;
+
+	FLAC__ASSERT(0 != decoder);
+
+	/*
+	 * To make sure that our file does not go unclosed after an error, we
+	 * have to do the same entrance checks here that are later performed
+	 * in FLAC__stream_decoder_init_FILE() before the FILE* is assigned.
+	 */
+	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+		return decoder->protected_->initstate = FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED;
+
+	if(0 == write_callback || 0 == error_callback)
+		return decoder->protected_->initstate = FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS;
+
+	file = filename? flac_fopen(filename, "rb") : stdin;
+
+	if(0 == file)
+		return FLAC__STREAM_DECODER_INIT_STATUS_ERROR_OPENING_FILE;
+
+	return init_FILE_internal_(decoder, file, write_callback, metadata_callback, error_callback, client_data, is_ogg);
+}
+
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_file(
+	FLAC__StreamDecoder *decoder,
+	const char *filename,
+	FLAC__StreamDecoderWriteCallback write_callback,
+	FLAC__StreamDecoderMetadataCallback metadata_callback,
+	FLAC__StreamDecoderErrorCallback error_callback,
+	void *client_data
+)
+{
+	return init_file_internal_(decoder, filename, write_callback, metadata_callback, error_callback, client_data, /*is_ogg=*/false);
+}
+
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_file(
+	FLAC__StreamDecoder *decoder,
+	const char *filename,
+	FLAC__StreamDecoderWriteCallback write_callback,
+	FLAC__StreamDecoderMetadataCallback metadata_callback,
+	FLAC__StreamDecoderErrorCallback error_callback,
+	void *client_data
+)
+{
+	return init_file_internal_(decoder, filename, write_callback, metadata_callback, error_callback, client_data, /*is_ogg=*/true);
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_finish(FLAC__StreamDecoder *decoder)
+{
+	FLAC__bool md5_failed = false;
 	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;
-	if(0 != decoder->private_->seek_table.data.seek_table.points) {
+		return true;
+
+	/* see the comment in FLAC__stream_decoder_reset() as to why we
+	 * always call FLAC__MD5Final()
+	 */
+	FLAC__MD5Final(decoder->private_->computed_md5sum, &decoder->private_->md5context);
+
+	if(decoder->private_->has_seek_table && 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);
+	FLAC__bitreader_free(decoder->private_->input);
 	for(i = 0; i < FLAC__MAX_CHANNELS; i++) {
 		/* WATCHOUT:
 		 * FLAC__lpc_restore_signal_asm_ia32_mmx() requires that the
@@ -363,23 +680,31 @@
 	decoder->private_->output_capacity = 0;
 	decoder->private_->output_channels = 0;
 
+#if FLAC__HAS_OGG
+	if(decoder->private_->is_ogg)
+		FLAC__ogg_decoder_aspect_finish(&decoder->protected_->ogg_decoder_aspect);
+#endif
+
+	if(0 != decoder->private_->file) {
+		if(decoder->private_->file != stdin)
+			fclose(decoder->private_->file);
+		decoder->private_->file = 0;
+	}
+
+	if(decoder->private_->do_md5_checking) {
+		if(memcmp(decoder->private_->stream_info.data.stream_info.md5sum, decoder->private_->computed_md5sum, 16))
+			md5_failed = true;
+	}
+	decoder->private_->is_seeking = false;
+
 	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;
+	return !md5_failed;
 }
 
-FLAC_API FLAC__bool FLAC__stream_decoder_set_write_callback(FLAC__StreamDecoder *decoder, FLAC__StreamDecoderWriteCallback value)
+FLAC_API FLAC__bool FLAC__stream_decoder_set_ogg_serial_number(FLAC__StreamDecoder *decoder, long value)
 {
 	FLAC__ASSERT(0 != decoder);
 	FLAC__ASSERT(0 != decoder->private_);
@@ -386,43 +711,26 @@
 	FLAC__ASSERT(0 != decoder->protected_);
 	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
 		return false;
-	decoder->private_->write_callback = value;
+#if FLAC__HAS_OGG
+	/* can't check decoder->private_->is_ogg since that's not set until init time */
+	FLAC__ogg_decoder_aspect_set_serial_number(&decoder->protected_->ogg_decoder_aspect, value);
 	return true;
+#else
+	(void)value;
+	return false;
+#endif
 }
 
-FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_callback(FLAC__StreamDecoder *decoder, FLAC__StreamDecoderMetadataCallback value)
+FLAC_API FLAC__bool FLAC__stream_decoder_set_md5_checking(FLAC__StreamDecoder *decoder, FLAC__bool 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;
+	decoder->protected_->md5_checking = 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);
@@ -455,8 +763,10 @@
 	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;
+		if(0 == (decoder->private_->metadata_filter_ids = safe_realloc_mul_2op_(decoder->private_->metadata_filter_ids, decoder->private_->metadata_filter_ids_capacity, /*times*/2))) {
+			decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+			return false;
+		}
 		decoder->private_->metadata_filter_ids_capacity *= 2;
 	}
 
@@ -512,8 +822,10 @@
 	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;
+		if(0 == (decoder->private_->metadata_filter_ids = safe_realloc_mul_2op_(decoder->private_->metadata_filter_ids, decoder->private_->metadata_filter_ids_capacity, /*times*/2))) {
+			decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+			return false;
+		}
 		decoder->private_->metadata_filter_ids_capacity *= 2;
 	}
 
@@ -547,6 +859,20 @@
 	return FLAC__StreamDecoderStateString[decoder->protected_->state];
 }
 
+FLAC_API FLAC__bool FLAC__stream_decoder_get_md5_checking(const FLAC__StreamDecoder *decoder)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->protected_);
+	return decoder->protected_->md5_checking;
+}
+
+FLAC_API FLAC__uint64 FLAC__stream_decoder_get_total_samples(const FLAC__StreamDecoder *decoder)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->protected_);
+	return decoder->private_->has_stream_info? decoder->private_->stream_info.data.stream_info.total_samples : 0;
+}
+
 FLAC_API unsigned FLAC__stream_decoder_get_channels(const FLAC__StreamDecoder *decoder)
 {
 	FLAC__ASSERT(0 != decoder);
@@ -582,6 +908,28 @@
 	return decoder->protected_->blocksize;
 }
 
+FLAC_API FLAC__bool FLAC__stream_decoder_get_decode_position(const FLAC__StreamDecoder *decoder, FLAC__uint64 *position)
+{
+	FLAC__ASSERT(0 != decoder);
+	FLAC__ASSERT(0 != decoder->private_);
+	FLAC__ASSERT(0 != position);
+
+#if FLAC__HAS_OGG
+	if(decoder->private_->is_ogg)
+		return false;
+#endif
+	if(0 == decoder->private_->tell_callback)
+		return false;
+	if(decoder->private_->tell_callback(decoder, position, decoder->private_->client_data) != FLAC__STREAM_DECODER_TELL_STATUS_OK)
+		return false;
+	/* should never happen since all FLAC frames and metadata blocks are byte aligned, but check just in case */
+	if(!FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input))
+		return false;
+	FLAC__ASSERT(*position >= FLAC__stream_decoder_get_input_bytes_unconsumed(decoder));
+	*position -= FLAC__stream_decoder_get_input_bytes_unconsumed(decoder);
+	return true;
+}
+
 FLAC_API FLAC__bool FLAC__stream_decoder_flush(FLAC__StreamDecoder *decoder)
 {
 	FLAC__ASSERT(0 != decoder);
@@ -588,7 +936,15 @@
 	FLAC__ASSERT(0 != decoder->private_);
 	FLAC__ASSERT(0 != decoder->protected_);
 
-	if(!FLAC__bitbuffer_clear(decoder->private_->input)) {
+	decoder->private_->samples_decoded = 0;
+	decoder->private_->do_md5_checking = false;
+
+#if FLAC__HAS_OGG
+	if(decoder->private_->is_ogg)
+		FLAC__ogg_decoder_aspect_flush(&decoder->protected_->ogg_decoder_aspect);
+#endif
+
+	if(!FLAC__bitreader_clear(decoder->private_->input)) {
 		decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
 		return false;
 	}
@@ -604,13 +960,56 @@
 	FLAC__ASSERT(0 != decoder->protected_);
 
 	if(!FLAC__stream_decoder_flush(decoder)) {
-		decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+		/* above call sets the state for us */
 		return false;
 	}
+
+#if FLAC__HAS_OGG
+	/*@@@ could go in !internal_reset_hack block below */
+	if(decoder->private_->is_ogg)
+		FLAC__ogg_decoder_aspect_reset(&decoder->protected_->ogg_decoder_aspect);
+#endif
+
+	/* Rewind if necessary.  If FLAC__stream_decoder_init() is calling us,
+	 * (internal_reset_hack) don't try to rewind since we are already at
+	 * the beginning of the stream and don't want to fail if the input is
+	 * not seekable.
+	 */
+	if(!decoder->private_->internal_reset_hack) {
+		if(decoder->private_->file == stdin)
+			return false; /* can't rewind stdin, reset fails */
+		if(decoder->private_->seek_callback && decoder->private_->seek_callback(decoder, 0, decoder->private_->client_data) == FLAC__STREAM_DECODER_SEEK_STATUS_ERROR)
+			return false; /* seekable and seek fails, reset fails */
+	}
+	else
+		decoder->private_->internal_reset_hack = false;
+
 	decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_METADATA;
 
-	decoder->private_->samples_decoded = 0;
+	decoder->private_->has_stream_info = false;
+	if(decoder->private_->has_seek_table && 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;
+	}
+	decoder->private_->do_md5_checking = decoder->protected_->md5_checking;
+	/*
+	 * This goes in reset() and not flush() because according to the spec, a
+	 * fixed-blocksize stream must stay that way through the whole stream.
+	 */
+	decoder->private_->fixed_block_size = decoder->private_->next_fixed_block_size = 0;
 
+	/* 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 init the context here and finalize it in
+	 * FLAC__stream_decoder_finish() to make sure things are always cleaned up
+	 * properly.
+	 */
+	FLAC__MD5Init(&decoder->private_->md5context);
+
+	decoder->private_->first_frame_offset = 0;
+	decoder->private_->unparseable_frame_count = 0;
+
 	return true;
 }
 
@@ -743,6 +1142,73 @@
 	}
 }
 
+FLAC_API FLAC__bool FLAC__stream_decoder_seek_absolute(FLAC__StreamDecoder *decoder, FLAC__uint64 sample)
+{
+	FLAC__uint64 length;
+
+	FLAC__ASSERT(0 != decoder);
+
+	if(
+		decoder->protected_->state != FLAC__STREAM_DECODER_SEARCH_FOR_METADATA &&
+		decoder->protected_->state != FLAC__STREAM_DECODER_READ_METADATA &&
+		decoder->protected_->state != FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC &&
+		decoder->protected_->state != FLAC__STREAM_DECODER_READ_FRAME &&
+		decoder->protected_->state != FLAC__STREAM_DECODER_END_OF_STREAM
+	)
+		return false;
+
+	if(0 == decoder->private_->seek_callback)
+		return false;
+
+	FLAC__ASSERT(decoder->private_->seek_callback);
+	FLAC__ASSERT(decoder->private_->tell_callback);
+	FLAC__ASSERT(decoder->private_->length_callback);
+	FLAC__ASSERT(decoder->private_->eof_callback);
+
+	if(FLAC__stream_decoder_get_total_samples(decoder) > 0 && sample >= FLAC__stream_decoder_get_total_samples(decoder))
+		return false;
+
+	decoder->private_->is_seeking = true;
+
+	/* turn off md5 checking if a seek is attempted */
+	decoder->private_->do_md5_checking = false;
+
+	/* get the file length (currently our algorithm needs to know the length so it's also an error to get FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED) */
+	if(decoder->private_->length_callback(decoder, &length, decoder->private_->client_data) != FLAC__STREAM_DECODER_LENGTH_STATUS_OK) {
+		decoder->private_->is_seeking = false;
+		return false;
+	}
+
+	/* if we haven't finished processing the metadata yet, do that so we have the STREAMINFO, SEEK_TABLE, and first_frame_offset */
+	if(
+		decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_METADATA ||
+		decoder->protected_->state == FLAC__STREAM_DECODER_READ_METADATA
+	) {
+		if(!FLAC__stream_decoder_process_until_end_of_metadata(decoder)) {
+			/* above call sets the state for us */
+			decoder->private_->is_seeking = false;
+			return false;
+		}
+		/* check this again in case we didn't know total_samples the first time */
+		if(FLAC__stream_decoder_get_total_samples(decoder) > 0 && sample >= FLAC__stream_decoder_get_total_samples(decoder)) {
+			decoder->private_->is_seeking = false;
+			return false;
+		}
+	}
+
+	{
+		const FLAC__bool ok =
+#if FLAC__HAS_OGG
+			decoder->private_->is_ogg?
+			seek_to_absolute_sample_ogg_(decoder, length, sample) :
+#endif
+			seek_to_absolute_sample_(decoder, length, sample)
+		;
+		decoder->private_->is_seeking = false;
+		return ok;
+	}
+}
+
 /***********************************************************************
  *
  * Protected class methods
@@ -752,7 +1218,9 @@
 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);
+	FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input));
+	FLAC__ASSERT(!(FLAC__bitreader_get_input_bits_unconsumed(decoder->private_->input) & 7));
+	return FLAC__bitreader_get_input_bits_unconsumed(decoder->private_->input) / 8;
 }
 
 /***********************************************************************
@@ -763,7 +1231,14 @@
 
 void set_defaults_(FLAC__StreamDecoder *decoder)
 {
+#if FLAC__HAS_OGG
+	decoder->private_->is_ogg = false;
+#endif
 	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;
@@ -772,8 +1247,35 @@
 	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;
+
+	decoder->protected_->md5_checking = false;
+
+#if FLAC__HAS_OGG
+	FLAC__ogg_decoder_aspect_set_defaults(&decoder->protected_->ogg_decoder_aspect);
+#endif
 }
 
+/*
+ * This will forcibly set stdin to binary mode (for OSes that require it)
+ */
+FILE *get_binary_stdin_(void)
+{
+	/* 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);
+#elif defined __EMX__
+	setmode(fileno(stdin), O_BINARY);
+#endif
+
+	return stdin;
+}
+
 FLAC__bool allocate_output_(FLAC__StreamDecoder *decoder, unsigned size, unsigned channels)
 {
 	unsigned i;
@@ -802,7 +1304,7 @@
 		 * (at negative indices) for alignment purposes; we use 4
 		 * to keep the data well-aligned.
 		 */
-		tmp = (FLAC__int32*)malloc(sizeof(FLAC__int32)*(size+4));
+		tmp = safe_malloc_muladd2_(sizeof(FLAC__int32), /*times (*/size, /*+*/4/*)*/);
 		if(tmp == 0) {
 			decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
 			return false;
@@ -810,9 +1312,6 @@
 		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;
@@ -827,7 +1326,7 @@
 
 FLAC__bool has_id_filtered_(FLAC__StreamDecoder *decoder, FLAC__byte *id)
 {
-	unsigned i;
+	size_t i;
 
 	FLAC__ASSERT(0 != decoder);
 	FLAC__ASSERT(0 != decoder->private_);
@@ -845,7 +1344,7 @@
 	unsigned i, id;
 	FLAC__bool first = true;
 
-	FLAC__ASSERT(FLAC__bitbuffer_is_consumed_byte_aligned(decoder->private_->input));
+	FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input));
 
 	for(i = id = 0; i < 4; ) {
 		if(decoder->private_->cached) {
@@ -853,8 +1352,8 @@
 			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(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8))
+				return false; /* read_callback_ sets the state for us */
 		}
 		if(x == FLAC__STREAM_SYNC_STRING[i]) {
 			first = true;
@@ -862,19 +1361,24 @@
 			id = 0;
 			continue;
 		}
+
+		if(id >= 3)
+			return false;
+
 		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 */
+					return false; /* skip_id3v2_tag_ sets the state for us */
 			}
 			continue;
 		}
+		id = 0;
 		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 */
+			if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8))
+				return false; /* 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 */
@@ -882,7 +1386,7 @@
 				decoder->private_->lookahead = (FLAC__byte)x;
 				decoder->private_->cached = true;
 			}
-			else if(x >> 2 == 0x3e) { /* MAGIC NUMBER for the last 6 sync bits */
+			else if(x >> 1 == 0x7c) { /* MAGIC NUMBER for the last 6 sync bits and reserved 7th bit */
 				decoder->private_->header_warmup[1] = (FLAC__byte)x;
 				decoder->protected_->state = FLAC__STREAM_DECODER_READ_FRAME;
 				return true;
@@ -890,7 +1394,7 @@
 		}
 		i = 0;
 		if(first) {
-			decoder->private_->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC, decoder->private_->client_data);
+			send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC);
 			first = false;
 		}
 	}
@@ -904,17 +1408,17 @@
 	FLAC__bool is_last;
 	FLAC__uint32 i, x, type, length;
 
-	FLAC__ASSERT(FLAC__bitbuffer_is_consumed_byte_aligned(decoder->private_->input));
+	FLAC__ASSERT(FLAC__bitreader_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 */
+	if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_IS_LAST_LEN))
+		return false; /* 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__bitreader_read_raw_uint32(decoder->private_->input, &type, FLAC__STREAM_METADATA_TYPE_LEN))
+		return false; /* 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(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &length, FLAC__STREAM_METADATA_LENGTH_LEN))
+		return false; /* read_callback_ sets the state for us */
 
 	if(type == FLAC__METADATA_TYPE_STREAMINFO) {
 		if(!read_metadata_streaminfo_(decoder, is_last, length))
@@ -921,7 +1425,9 @@
 			return false;
 
 		decoder->private_->has_stream_info = true;
-		if(decoder->private_->metadata_filter[FLAC__METADATA_TYPE_STREAMINFO])
+		if(0 == memcmp(decoder->private_->stream_info.data.stream_info.md5sum, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16))
+			decoder->private_->do_md5_checking = false;
+		if(!decoder->private_->is_seeking && decoder->private_->metadata_filter[FLAC__METADATA_TYPE_STREAMINFO] && decoder->private_->metadata_callback)
 			decoder->private_->metadata_callback(decoder, &decoder->private_->stream_info, decoder->private_->client_data);
 	}
 	else if(type == FLAC__METADATA_TYPE_SEEKTABLE) {
@@ -929,7 +1435,7 @@
 			return false;
 
 		decoder->private_->has_seek_table = true;
-		if(decoder->private_->metadata_filter[FLAC__METADATA_TYPE_SEEKTABLE])
+		if(!decoder->private_->is_seeking && decoder->private_->metadata_filter[FLAC__METADATA_TYPE_SEEKTABLE] && decoder->private_->metadata_callback)
 			decoder->private_->metadata_callback(decoder, &decoder->private_->seek_table, decoder->private_->client_data);
 	}
 	else {
@@ -937,14 +1443,20 @@
 		unsigned real_length = length;
 		FLAC__StreamMetadata block;
 
+		memset(&block, 0, sizeof(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 */
+			if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, block.data.application.id, FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8))
+				return false; /* read_callback_ sets the state for us */
 
+			if(real_length < FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) { /* underflow check */
+				decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;/*@@@@@@ maybe wrong error? need to resync?*/
+				return false;
+			}
+
 			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))
@@ -952,37 +1464,42 @@
 		}
 
 		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 */
+			if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(decoder->private_->input, real_length))
+				return false; /* read_callback_ sets the state for us */
 		}
 		else {
+			FLAC__bool ok = true;
 			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 */
+					if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(decoder->private_->input, real_length))
+						ok = false; /* 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))) {
+						if(0 == (block.data.application.data = malloc(real_length))) {
 							decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
-							return false;
+							ok = 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 if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, block.data.application.data, real_length))
+							ok = false; /* 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;
+					if(!read_metadata_vorbiscomment_(decoder, &block.data.vorbis_comment, real_length))
+						ok = false;
 					break;
 				case FLAC__METADATA_TYPE_CUESHEET:
 					if(!read_metadata_cuesheet_(decoder, &block.data.cue_sheet))
-						return false;
+						ok = false;
 					break;
+				case FLAC__METADATA_TYPE_PICTURE:
+					if(!read_metadata_picture_(decoder, &block.data.picture))
+						ok = false;
+					break;
 				case FLAC__METADATA_TYPE_STREAMINFO:
 				case FLAC__METADATA_TYPE_SEEKTABLE:
 					FLAC__ASSERT(0);
@@ -989,20 +1506,21 @@
 					break;
 				default:
 					if(real_length > 0) {
-						if(0 == (block.data.unknown.data = (FLAC__byte*)malloc(real_length))) {
+						if(0 == (block.data.unknown.data = malloc(real_length))) {
 							decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
-							return false;
+							ok = 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 if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, block.data.unknown.data, real_length))
+							ok = false; /* read_callback_ sets the state for us */
 					}
 					else
 						block.data.unknown.data = 0;
 					break;
 			}
-			decoder->private_->metadata_callback(decoder, &block, decoder->private_->client_data);
+			if(ok && !decoder->private_->is_seeking && decoder->private_->metadata_callback)
+				decoder->private_->metadata_callback(decoder, &block, decoder->private_->client_data);
 
-			/* now we have to free any malloc'ed data in the block */
+			/* now we have to free any malloc()ed data in the block */
 			switch(type) {
 				case FLAC__METADATA_TYPE_PADDING:
 					break;
@@ -1028,6 +1546,14 @@
 					if(0 != block.data.cue_sheet.tracks)
 						free(block.data.cue_sheet.tracks);
 					break;
+				case FLAC__METADATA_TYPE_PICTURE:
+					if(0 != block.data.picture.mime_type)
+						free(block.data.picture.mime_type);
+					if(0 != block.data.picture.description)
+						free(block.data.picture.description);
+					if(0 != block.data.picture.data)
+						free(block.data.picture.data);
+					break;
 				case FLAC__METADATA_TYPE_STREAMINFO:
 				case FLAC__METADATA_TYPE_SEEKTABLE:
 					FLAC__ASSERT(0);
@@ -1036,11 +1562,18 @@
 						free(block.data.unknown.data);
 					break;
 			}
+
+			if(!ok) /* anything that unsets "ok" should also make sure decoder->protected_->state is updated */
+				return false;
 		}
 	}
 
-	if(is_last)
+	if(is_last) {
+		/* if this fails, it's OK, it's just a hint for the seek routine */
+		if(!FLAC__stream_decoder_get_decode_position(decoder, &decoder->private_->first_frame_offset))
+			decoder->private_->first_frame_offset = 0;
 		decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+	}
 
 	return true;
 }
@@ -1050,7 +1583,7 @@
 	FLAC__uint32 x;
 	unsigned bits, used_bits = 0;
 
-	FLAC__ASSERT(FLAC__bitbuffer_is_consumed_byte_aligned(decoder->private_->input));
+	FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input));
 
 	decoder->private_->stream_info.type = FLAC__METADATA_TYPE_STREAMINFO;
 	decoder->private_->stream_info.is_last = is_last;
@@ -1057,61 +1590,61 @@
 	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 */
+	if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, bits))
+		return false; /* 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 */
+	if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN))
+		return false; /* 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 */
+	if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN))
+		return false; /* 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 */
+	if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN))
+		return false; /* 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 */
+	if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN))
+		return false; /* 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 */
+	if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN))
+		return false; /* 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 */
+	if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN))
+		return false; /* 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 */
+	if(!FLAC__bitreader_read_raw_uint64(decoder->private_->input, &decoder->private_->stream_info.data.stream_info.total_samples, FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN))
+		return false; /* 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 */
+	if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, decoder->private_->stream_info.data.stream_info.md5sum, 16))
+		return false; /* 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 */
+	if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(decoder->private_->input, length))
+		return false; /* read_callback_ sets the state for us */
 
 	return true;
 }
@@ -1121,7 +1654,7 @@
 	FLAC__uint32 i, x;
 	FLAC__uint64 xx;
 
-	FLAC__ASSERT(FLAC__bitbuffer_is_consumed_byte_aligned(decoder->private_->input));
+	FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input));
 
 	decoder->private_->seek_table.type = FLAC__METADATA_TYPE_SEEKTABLE;
 	decoder->private_->seek_table.is_last = is_last;
@@ -1130,84 +1663,116 @@
 	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)))) {
+	if(0 == (decoder->private_->seek_table.data.seek_table.points = safe_realloc_mul_2op_(decoder->private_->seek_table.data.seek_table.points, decoder->private_->seek_table.data.seek_table.num_points, /*times*/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 */
+		if(!FLAC__bitreader_read_raw_uint64(decoder->private_->input, &xx, FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN))
+			return false; /* 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 */
+		if(!FLAC__bitreader_read_raw_uint64(decoder->private_->input, &xx, FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN))
+			return false; /* 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 */
+		if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN))
+			return false; /* 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 */
+		/*@@@ do a send_error_to_client_() here?  there's an argument for either way */
+		if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(decoder->private_->input, length))
+			return false; /* read_callback_ sets the state for us */
 	}
 
 	return true;
 }
 
-FLAC__bool read_metadata_vorbiscomment_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_VorbisComment *obj)
+FLAC__bool read_metadata_vorbiscomment_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_VorbisComment *obj, unsigned length)
 {
 	FLAC__uint32 i;
 
-	FLAC__ASSERT(FLAC__bitbuffer_is_consumed_byte_aligned(decoder->private_->input));
+	FLAC__ASSERT(FLAC__bitreader_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 (length >= 8) {
+		length -= 8; /* vendor string length + num comments entries alone take 8 bytes */
+		FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN == 32);
+		if (!FLAC__bitreader_read_uint32_little_endian(decoder->private_->input, &obj->vendor_string.length))
+			return false; /* read_callback_ sets the state for us */
+		if (obj->vendor_string.length > 0) {
+			if (length < obj->vendor_string.length) {
+				obj->vendor_string.length = 0;
+				obj->vendor_string.entry = 0;
+				goto skip;
+			}
+			else
+				length -= obj->vendor_string.length;
+			if (0 == (obj->vendor_string.entry = safe_malloc_add_2op_(obj->vendor_string.length, /*+*/1))) {
+				decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+				return false;
+			}
+			if (!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, obj->vendor_string.entry, obj->vendor_string.length))
+				return false; /* read_callback_ sets the state for us */
+			obj->vendor_string.entry[obj->vendor_string.length] = '\0';
 		}
-		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;
+		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 num comments */
+		FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN == 32);
+		if (!FLAC__bitreader_read_uint32_little_endian(decoder->private_->input, &obj->num_comments))
+			return false; /* 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;
+		/* read comments */
+		if (obj->num_comments > 0) {
+			if (0 == (obj->comments = safe_malloc_mul_2op_p(obj->num_comments, /*times*/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 (length < 4) {
+					obj->num_comments = i;
+					goto skip;
 				}
-				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
+					length -= 4;
+				if (!FLAC__bitreader_read_uint32_little_endian(decoder->private_->input, &obj->comments[i].length))
+					return false; /* read_callback_ sets the state for us */
+				if (obj->comments[i].length > 0) {
+					if (length < obj->comments[i].length) {
+						obj->comments[i].length = 0;
+						obj->comments[i].entry = 0;
+						obj->num_comments = i;
+						goto skip;
+					}
+					else
+						length -= obj->comments[i].length;
+					if (0 == (obj->comments[i].entry = safe_malloc_add_2op_(obj->comments[i].length, /*+*/1))) {
+						decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+						return false;
+					}
+					if (!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, obj->comments[i].entry, obj->comments[i].length))
+						return false; /* read_callback_ sets the state for us */
+					obj->comments[i].entry[obj->comments[i].length] = '\0';
+				}
+				else
+					obj->comments[i].entry = 0;
 			}
-			else
-				obj->comments[i].entry = 0;
 		}
+		else
+			obj->comments = 0;
 	}
-	else {
-		obj->comments = 0;
+
+  skip:
+	if (length > 0) {
+		/* This will only happen on files with invalid data in comments */
+		if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(decoder->private_->input, length))
+			return false; /* read_callback_ sets the state for us */
 	}
 
 	return true;
@@ -1217,77 +1782,77 @@
 {
 	FLAC__uint32 i, j, x;
 
-	FLAC__ASSERT(FLAC__bitbuffer_is_consumed_byte_aligned(decoder->private_->input));
+	FLAC__ASSERT(FLAC__bitreader_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__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, (FLAC__byte*)obj->media_catalog_number, FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN/8))
+		return false; /* 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__bitreader_read_raw_uint64(decoder->private_->input, &obj->lead_in, FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN))
+		return false; /* 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 */
+	if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN))
+		return false; /* 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__bitreader_skip_bits_no_crc(decoder->private_->input, FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN))
+		return false; /* 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 */
+	if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN))
+		return false; /* 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)))) {
+		if(0 == (obj->tracks = safe_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__bitreader_read_raw_uint64(decoder->private_->input, &track->offset, FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN))
+				return false; /* 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 */
+			if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN))
+				return false; /* 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__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, (FLAC__byte*)track->isrc, FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN/8))
+				return false; /* 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 */
+			if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN))
+				return false; /* 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 */
+			if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN))
+				return false; /* 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__bitreader_skip_bits_no_crc(decoder->private_->input, FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN))
+				return false; /* 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 */
+			if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN))
+				return false; /* 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)))) {
+				if(0 == (track->indices = safe_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 */
+					FLAC__StreamMetadata_CueSheet_Index *indx = &track->indices[j];
+					if(!FLAC__bitreader_read_raw_uint64(decoder->private_->input, &indx->offset, FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN))
+						return false; /* 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__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN))
+						return false; /* read_callback_ sets the state for us */
+					indx->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 */
+					if(!FLAC__bitreader_skip_bits_no_crc(decoder->private_->input, FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN))
+						return false; /* read_callback_ sets the state for us */
 				}
 			}
 		}
@@ -1296,6 +1861,74 @@
 	return true;
 }
 
+FLAC__bool read_metadata_picture_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_Picture *obj)
+{
+	FLAC__uint32 x;
+
+	FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input));
+
+	/* read type */
+	if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_PICTURE_TYPE_LEN))
+		return false; /* read_callback_ sets the state for us */
+	obj->type = x;
+
+	/* read MIME type */
+	if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN))
+		return false; /* read_callback_ sets the state for us */
+	if(0 == (obj->mime_type = safe_malloc_add_2op_(x, /*+*/1))) {
+		decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+		return false;
+	}
+	if(x > 0) {
+		if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, (FLAC__byte*)obj->mime_type, x))
+			return false; /* read_callback_ sets the state for us */
+	}
+	obj->mime_type[x] = '\0';
+
+	/* read description */
+	if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN))
+		return false; /* read_callback_ sets the state for us */
+	if(0 == (obj->description = safe_malloc_add_2op_(x, /*+*/1))) {
+		decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+		return false;
+	}
+	if(x > 0) {
+		if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, obj->description, x))
+			return false; /* read_callback_ sets the state for us */
+	}
+	obj->description[x] = '\0';
+
+	/* read width */
+	if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &obj->width, FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN))
+		return false; /* read_callback_ sets the state for us */
+
+	/* read height */
+	if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &obj->height, FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN))
+		return false; /* read_callback_ sets the state for us */
+
+	/* read depth */
+	if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &obj->depth, FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN))
+		return false; /* read_callback_ sets the state for us */
+
+	/* read colors */
+	if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &obj->colors, FLAC__STREAM_METADATA_PICTURE_COLORS_LEN))
+		return false; /* read_callback_ sets the state for us */
+
+	/* read data */
+	if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &(obj->data_length), FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN))
+		return false; /* read_callback_ sets the state for us */
+	if(0 == (obj->data = safe_malloc_(obj->data_length))) {
+		decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+		return false;
+	}
+	if(obj->data_length > 0) {
+		if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, obj->data, obj->data_length))
+			return false; /* read_callback_ sets the state for us */
+	}
+
+	return true;
+}
+
 FLAC__bool skip_id3v2_tag_(FLAC__StreamDecoder *decoder)
 {
 	FLAC__uint32 x;
@@ -1302,19 +1935,19 @@
 	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 */
+	if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 24))
+		return false; /* 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 */
+		if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8))
+			return false; /* 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 */
+	if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(decoder->private_->input, skip))
+		return false; /* read_callback_ sets the state for us */
 	return true;
 }
 
@@ -1325,8 +1958,8 @@
 
 	/* 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) {
+	if(FLAC__stream_decoder_get_total_samples(decoder) > 0) {
+		if(decoder->private_->samples_decoded >= FLAC__stream_decoder_get_total_samples(decoder)) {
 			decoder->protected_->state = FLAC__STREAM_DECODER_END_OF_STREAM;
 			return true;
 		}
@@ -1333,9 +1966,9 @@
 	}
 
 	/* 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 */
+	if(!FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)) {
+		if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__bitreader_bits_left_for_byte_alignment(decoder->private_->input)))
+			return false; /* read_callback_ sets the state for us */
 	}
 
 	while(1) {
@@ -1344,13 +1977,13 @@
 			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(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8))
+				return false; /* 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 */
+			if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8))
+				return false; /* 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 */
@@ -1358,7 +1991,7 @@
 				decoder->private_->lookahead = (FLAC__byte)x;
 				decoder->private_->cached = true;
 			}
-			else if(x >> 2 == 0x3e) { /* MAGIC NUMBER for the last 6 sync bits */
+			else if(x >> 1 == 0x7c) { /* MAGIC NUMBER for the last 6 sync bits and reserved 7th bit */
 				decoder->private_->header_warmup[1] = (FLAC__byte)x;
 				decoder->protected_->state = FLAC__STREAM_DECODER_READ_FRAME;
 				return true;
@@ -1365,7 +1998,7 @@
 			}
 		}
 		if(first) {
-			decoder->private_->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC, decoder->private_->client_data);
+			send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC);
 			first = false;
 		}
 	}
@@ -1377,8 +2010,8 @@
 {
 	unsigned channel;
 	unsigned i;
-	FLAC__int32 mid, side, left, right;
-	FLAC__uint16 frame_crc; /* the one we calculate from the input stream */
+	FLAC__int32 mid, side;
+	unsigned frame_crc; /* the one we calculate from the input stream */
 	FLAC__uint32 x;
 
 	*got_a_frame = false;
@@ -1385,13 +2018,13 @@
 
 	/* 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);
+	frame_crc = FLAC__CRC16_UPDATE(decoder->private_->header_warmup[0], frame_crc);
+	frame_crc = FLAC__CRC16_UPDATE(decoder->private_->header_warmup[1], frame_crc);
+	FLAC__bitreader_reset_read_crc16(decoder->private_->input, (FLAC__uint16)frame_crc);
 
 	if(!read_frame_header_(decoder))
 		return false;
-	if(decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC)
+	if(decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC) /* means we didn't sync on a valid header */
 		return true;
 	if(!allocate_output_(decoder, decoder->private_->frame.header.blocksize, decoder->private_->frame.header.channels))
 		return false;
@@ -1427,21 +2060,21 @@
 		 */
 		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;
+		if(decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC) /* means bad sync or got corruption */
 			return true;
-		}
 	}
 	if(!read_zero_padding_(decoder))
 		return false;
+	if(decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC) /* means bad sync or got corruption (i.e. "zero bits" were not all zeroes) */
+		return true;
 
 	/*
 	 * 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) {
+	frame_crc = FLAC__bitreader_get_read_crc16(decoder->private_->input);
+	if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__FRAME_FOOTER_CRC_LEN))
+		return false; /* read_callback_ sets the state for us */
+	if(frame_crc == x) {
 		if(do_full_decode) {
 			/* Undo any special channel coding */
 			switch(decoder->private_->frame.header.channel_assignment) {
@@ -1461,15 +2094,19 @@
 				case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE:
 					FLAC__ASSERT(decoder->private_->frame.header.channels == 2);
 					for(i = 0; i < decoder->private_->frame.header.blocksize; i++) {
+#if 1
 						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;
+						mid |= (side & 1); /* i.e. if 'side' is odd... */
+						decoder->private_->output[0][i] = (mid + side) >> 1;
+						decoder->private_->output[1][i] = (mid - side) >> 1;
+#else
+						/* OPT: without 'side' temp variable */
+						mid = (decoder->private_->output[0][i] << 1) | (decoder->private_->output[1][i] & 1); /* i.e. if 'side' is odd... */
+						decoder->private_->output[0][i] = (mid + decoder->private_->output[1][i]) >> 1;
+						decoder->private_->output[1][i] = (mid - decoder->private_->output[1][i]) >> 1;
+#endif
 					}
 					break;
 				default:
@@ -1480,7 +2117,7 @@
 	}
 	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);
+		send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH);
 		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);
@@ -1490,6 +2127,10 @@
 
 	*got_a_frame = true;
 
+	/* we wait to update fixed_block_size until here, when we're sure we've got a proper frame and hence a correct blocksize */
+	if(decoder->private_->next_fixed_block_size)
+		decoder->private_->fixed_block_size = decoder->private_->next_fixed_block_size;
+
 	/* 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;
@@ -1502,7 +2143,7 @@
 
 	/* 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)
+		if(write_audio_frame_to_client_(decoder, &decoder->private_->frame, (const FLAC__int32 * const *)decoder->private_->output) != FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE)
 			return false;
 	}
 
@@ -1518,10 +2159,8 @@
 	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));
+	FLAC__ASSERT(FLAC__bitreader_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];
@@ -1528,17 +2167,27 @@
 	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 */
+	/* check to make sure that reserved bit is 0 */
+	if(raw_header[1] & 0x02) /* 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.
+	 *
+	 * Three kinds of things can go wrong when reading the frame header:
+	 *  1) We may have sync'ed incorrectly and not landed on a frame header.
+	 *     If we don't find a sync code, it can end up looking like we read
+	 *     a valid but unparseable header, until getting to the frame header
+	 *     CRC.  Even then we could get a false positive on the CRC.
+	 *  2) We may have sync'ed correctly but on an unparseable frame (from a
+	 *     future encoder).
+	 *  3) We may be on a damaged frame which appears valid but unparseable.
+	 *
+	 * For all these reasons, we try and read a complete frame header as
+	 * long as it seems valid, even if unparseable, up until the frame
+	 * header CRC.
 	 */
 
 	/*
@@ -1545,13 +2194,13 @@
 	 * 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(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8))
+			return false; /* 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);
+			send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER);
 			decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
 			return true;
 		}
@@ -1560,10 +2209,7 @@
 
 	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;
+			is_unparseable = true;
 			break;
 		case 1:
 			decoder->private_->frame.header.blocksize = 192;
@@ -1601,9 +2247,13 @@
 				is_unparseable = true;
 			break;
 		case 1:
+			decoder->private_->frame.header.sample_rate = 88200;
+			break;
 		case 2:
+			decoder->private_->frame.header.sample_rate = 176400;
+			break;
 		case 3:
-			is_unparseable = true;
+			decoder->private_->frame.header.sample_rate = 192000;
 			break;
 		case 4:
 			decoder->private_->frame.header.sample_rate = 8000;
@@ -1635,7 +2285,7 @@
 			sample_rate_hint = x;
 			break;
 		case 15:
-			decoder->private_->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER, decoder->private_->client_data);
+			send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER);
 			decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
 			return true;
 		default:
@@ -1696,19 +2346,22 @@
 			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;
-	}
+	/* check to make sure that reserved bit is 0 */
+	if(raw_header[3] & 0x01) /* MAGIC NUMBER */
+		is_unparseable = 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 */
+	/* read the frame's starting sample number (or frame number as the case may be) */
+	if(
+		raw_header[1] & 0x01 ||
+		/*@@@ this clause is a concession to the old way of doing variable blocksize; the only known implementation is flake and can probably be removed without inconveniencing anyone */
+		(decoder->private_->has_stream_info && decoder->private_->stream_info.data.stream_info.min_blocksize != decoder->private_->stream_info.data.stream_info.max_blocksize)
+	) { /* variable blocksize */
+		if(!FLAC__bitreader_read_utf8_uint64(decoder->private_->input, &xx, raw_header, &raw_header_len))
+			return false; /* 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);
+			send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER);
 			decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
 			return true;
 		}
@@ -1715,36 +2368,28 @@
 		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 */
+	else { /* fixed blocksize */
+		if(!FLAC__bitreader_read_utf8_uint32(decoder->private_->input, &x, raw_header, &raw_header_len))
+			return false; /* 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);
+			send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER);
 			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;
+		decoder->private_->frame.header.number_type = FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER;
+		decoder->private_->frame.header.number.frame_number = 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 */
+		if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8))
+			return false; /* 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 */
+			if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &_x, 8))
+				return false; /* read_callback_ sets the state for us */
 			raw_header[raw_header_len++] = (FLAC__byte)_x;
 			x = (x << 8) | _x;
 		}
@@ -1752,13 +2397,13 @@
 	}
 
 	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 */
+		if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8))
+			return false; /* 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 */
+			if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &_x, 8))
+				return false; /* read_callback_ sets the state for us */
 			raw_header[raw_header_len++] = (FLAC__byte)_x;
 			x = (x << 8) | _x;
 		}
@@ -1771,19 +2416,45 @@
 	}
 
 	/* 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 */
+	if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8))
+		return false; /* 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);
+		send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER);
 		decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
 		return true;
 	}
 
+	/* calculate the sample number from the frame number if needed */
+	decoder->private_->next_fixed_block_size = 0;
+	if(decoder->private_->frame.header.number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER) {
+		x = decoder->private_->frame.header.number.frame_number;
+		decoder->private_->frame.header.number_type = FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER;
+		if(decoder->private_->fixed_block_size)
+			decoder->private_->frame.header.number.sample_number = (FLAC__uint64)decoder->private_->fixed_block_size * (FLAC__uint64)x;
+		else if(decoder->private_->has_stream_info) {
+			if(decoder->private_->stream_info.data.stream_info.min_blocksize == decoder->private_->stream_info.data.stream_info.max_blocksize) {
+				decoder->private_->frame.header.number.sample_number = (FLAC__uint64)decoder->private_->stream_info.data.stream_info.min_blocksize * (FLAC__uint64)x;
+				decoder->private_->next_fixed_block_size = decoder->private_->stream_info.data.stream_info.max_blocksize;
+			}
+			else
+				is_unparseable = true;
+		}
+		else if(x == 0) {
+			decoder->private_->frame.header.number.sample_number = 0;
+			decoder->private_->next_fixed_block_size = decoder->private_->frame.header.blocksize;
+		}
+		else {
+			/* can only get here if the stream has invalid frame numbering and no STREAMINFO, so assume it's not the last (possibly short) frame */
+			decoder->private_->frame.header.number.sample_number = (FLAC__uint64)decoder->private_->frame.header.blocksize * (FLAC__uint64)x;
+		}
+	}
+
 	if(is_unparseable) {
-		decoder->protected_->state = FLAC__STREAM_DECODER_UNPARSEABLE_STREAM;
-		return false;
+		send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM);
+		decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+		return true;
 	}
 
 	return true;
@@ -1793,9 +2464,10 @@
 {
 	FLAC__uint32 x;
 	FLAC__bool wasted_bits;
+	unsigned i;
 
-	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 */
+	if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8)) /* MAGIC NUMBER */
+		return false; /* read_callback_ sets the state for us */
 
 	wasted_bits = (x & 1);
 	x &= 0xfe;
@@ -1802,8 +2474,8 @@
 
 	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 */
+		if(!FLAC__bitreader_read_unary_unsigned(decoder->private_->input, &u))
+			return false; /* read_callback_ sets the state for us */
 		decoder->private_->frame.subframes[channel].wasted_bits = u+1;
 		bps -= decoder->private_->frame.subframes[channel].wasted_bits;
 	}
@@ -1814,7 +2486,7 @@
 	 * Lots of magic numbers here
 	 */
 	if(x & 0x80) {
-		decoder->private_->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC, decoder->private_->client_data);
+		send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC);
 		decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
 		return true;
 	}
@@ -1827,24 +2499,29 @@
 			return false;
 	}
 	else if(x < 16) {
-		decoder->protected_->state = FLAC__STREAM_DECODER_UNPARSEABLE_STREAM;
-		return false;
+		send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM);
+		decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+		return true;
 	}
 	else if(x <= 24) {
 		if(!read_subframe_fixed_(decoder, channel, bps, (x>>1)&7, do_full_decode))
 			return false;
+		if(decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC) /* means bad sync or got corruption */
+			return true;
 	}
 	else if(x < 64) {
-		decoder->protected_->state = FLAC__STREAM_DECODER_UNPARSEABLE_STREAM;
-		return false;
+		send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM);
+		decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+		return true;
 	}
 	else {
 		if(!read_subframe_lpc_(decoder, channel, bps, ((x>>1)&31)+1, do_full_decode))
 			return false;
+		if(decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC) /* means bad sync or got corruption */
+			return true;
 	}
 
 	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;
@@ -1862,8 +2539,8 @@
 
 	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 */
+	if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &x, bps))
+		return false; /* read_callback_ sets the state for us */
 
 	subframe->value = x;
 
@@ -1890,31 +2567,34 @@
 
 	/* 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 */
+		if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &i32, bps))
+			return false; /* 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 */
+	if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &u32, FLAC__ENTROPY_CODING_METHOD_TYPE_LEN))
+		return false; /* 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 */
+		case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2:
+			if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &u32, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN))
+				return false; /* 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;
+			send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM);
+			decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+			return true;
 	}
 
 	/* 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]))
+		case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2:
+			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], /*is_extended=*/subframe->entropy_coding_method.type == FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2))
 				return false;
 			break;
 		default:
@@ -1944,16 +2624,16 @@
 
 	/* 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 */
+		if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &i32, bps))
+			return false; /* 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(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &u32, FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN))
+		return false; /* 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);
+		send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC);
 		decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
 		return true;
 	}
@@ -1960,37 +2640,40 @@
 	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 */
+	if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &i32, FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN))
+		return false; /* 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 */
+		if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &i32, subframe->qlp_coeff_precision))
+			return false; /* 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 */
+	if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &u32, FLAC__ENTROPY_CODING_METHOD_TYPE_LEN))
+		return false; /* 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 */
+		case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2:
+			if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &u32, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN))
+				return false; /* 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;
+			send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM);
+			decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+			return true;
 	}
 
 	/* 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]))
+		case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2:
+			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], /*is_extended=*/subframe->entropy_coding_method.type == FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2))
 				return false;
 			break;
 		default:
@@ -2000,13 +2683,12 @@
 	/* decode the subframe */
 	if(do_full_decode) {
 		memcpy(decoder->private_->output[channel], subframe->warmup, sizeof(FLAC__int32) * order);
+		/*@@@@@@ technically not pessimistic enough, should be more like
+		if( (FLAC__uint64)order * ((((FLAC__uint64)1)<<bps)-1) * ((1<<subframe->qlp_coeff_precision)-1) < (((FLAC__uint64)-1) << 32) )
+		*/
 		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);
-			}
+			if(bps <= 16 && subframe->qlp_coeff_precision <= 16)
+				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
@@ -2027,8 +2709,8 @@
 	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 */
+		if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &x, bps))
+			return false; /* read_callback_ sets the state for us */
 		residual[i] = x;
 	}
 
@@ -2039,7 +2721,7 @@
 	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__bool read_residual_partitioned_rice_(FLAC__StreamDecoder *decoder, unsigned predictor_order, unsigned partition_order, FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents, FLAC__int32 *residual, FLAC__bool is_extended)
 {
 	FLAC__uint32 rice_parameter;
 	int i;
@@ -2046,8 +2728,28 @@
 	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;
+	const unsigned plen = is_extended? FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN : FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN;
+	const unsigned pesc = is_extended? FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER : FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER;
 
-	if(!FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(partitioned_rice_contents, max(6, partition_order))) {
+	/* sanity checks */
+	if(partition_order == 0) {
+		if(decoder->private_->frame.header.blocksize < predictor_order) {
+			send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC);
+			decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+			/* We have received a potentially malicious bit stream. All we can do is error out to avoid a heap overflow. */
+			return false;
+		}
+	}
+	else {
+		if(partition_samples < predictor_order) {
+			send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC);
+			decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+			/* We have received a potentially malicious bit stream. All we can do is error out to avoid a heap overflow. */
+			return false;
+		}
+	}
+
+	if(!FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(partitioned_rice_contents, flac_max(6u, partition_order))) {
 		decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
 		return false;
 	}
@@ -2054,30 +2756,23 @@
 
 	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 */
+		if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &rice_parameter, plen))
+			return false; /* 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
+		if(rice_parameter < pesc) {
+			partitioned_rice_contents->raw_bits[partition] = 0;
 			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 */
+			if(!FLAC__bitreader_read_rice_signed_block(decoder->private_->input, residual + sample, u, rice_parameter))
+				return false; /* 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 */
+			if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &rice_parameter, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN))
+				return false; /* 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 */
+				if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &i, rice_parameter))
+					return false; /* read_callback_ sets the state for us */
 				residual[sample] = i;
 			}
 		}
@@ -2088,12 +2783,12 @@
 
 FLAC__bool read_zero_padding_(FLAC__StreamDecoder *decoder)
 {
-	if(!FLAC__bitbuffer_is_consumed_byte_aligned(decoder->private_->input)) {
+	if(!FLAC__bitreader_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(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &zero, FLAC__bitreader_bits_left_for_byte_alignment(decoder->private_->input)))
+			return false; /* 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);
+			send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC);
 			decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
 		}
 	}
@@ -2100,15 +2795,595 @@
 	return true;
 }
 
-FLAC__bool read_callback_(FLAC__byte buffer[], unsigned *bytes, void *client_data)
+FLAC__bool read_callback_(FLAC__byte buffer[], size_t *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)
+	if(
+#if FLAC__HAS_OGG
+		/* see [1] HACK NOTE below for why we don't call the eof_callback when decoding Ogg FLAC */
+		!decoder->private_->is_ogg &&
+#endif
+		decoder->private_->eof_callback && decoder->private_->eof_callback(decoder, decoder->private_->client_data)
+	) {
+		*bytes = 0;
 		decoder->protected_->state = FLAC__STREAM_DECODER_END_OF_STREAM;
-	else if(status == FLAC__STREAM_DECODER_READ_STATUS_ABORT)
+		return false;
+	}
+	else if(*bytes > 0) {
+		/* While seeking, 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, our
+		 * error callback will get an
+		 * FLAC__STREAM_DECODER_UNPARSEABLE_STREAM and increment its
+		 * unparseable_frame_count.  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 many "unparseable" errors in
+		 * a row before bailing out.
+		 */
+		if(decoder->private_->is_seeking && decoder->private_->unparseable_frame_count > 20) {
+			decoder->protected_->state = FLAC__STREAM_DECODER_ABORTED;
+			return false;
+		}
+		else {
+			const FLAC__StreamDecoderReadStatus status =
+#if FLAC__HAS_OGG
+				decoder->private_->is_ogg?
+				read_callback_ogg_aspect_(decoder, buffer, bytes) :
+#endif
+				decoder->private_->read_callback(decoder, buffer, bytes, decoder->private_->client_data)
+			;
+			if(status == FLAC__STREAM_DECODER_READ_STATUS_ABORT) {
+				decoder->protected_->state = FLAC__STREAM_DECODER_ABORTED;
+				return false;
+			}
+			else if(*bytes == 0) {
+				if(
+					status == FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM ||
+					(
+#if FLAC__HAS_OGG
+						/* see [1] HACK NOTE below for why we don't call the eof_callback when decoding Ogg FLAC */
+						!decoder->private_->is_ogg &&
+#endif
+						decoder->private_->eof_callback && decoder->private_->eof_callback(decoder, decoder->private_->client_data)
+					)
+				) {
+					decoder->protected_->state = FLAC__STREAM_DECODER_END_OF_STREAM;
+					return false;
+				}
+				else
+					return true;
+			}
+			else
+				return true;
+		}
+	}
+	else {
+		/* abort to avoid a deadlock */
 		decoder->protected_->state = FLAC__STREAM_DECODER_ABORTED;
-	return status == FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+		return false;
+	}
+	/* [1] @@@ HACK NOTE: The end-of-stream checking has to be hacked around
+	 * for Ogg FLAC.  This is because the ogg decoder aspect can lose sync
+	 * and at the same time hit the end of the stream (for example, seeking
+	 * to a point that is after the beginning of the last Ogg page).  There
+	 * is no way to report an Ogg sync loss through the callbacks (see note
+	 * in read_callback_ogg_aspect_()) so it returns CONTINUE with *bytes==0.
+	 * So to keep the decoder from stopping at this point we gate the call
+	 * to the eof_callback and let the Ogg decoder aspect set the
+	 * end-of-stream state when it is needed.
+	 */
+}
+
+#if FLAC__HAS_OGG
+FLAC__StreamDecoderReadStatus read_callback_ogg_aspect_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes)
+{
+	switch(FLAC__ogg_decoder_aspect_read_callback_wrapper(&decoder->protected_->ogg_decoder_aspect, buffer, bytes, read_callback_proxy_, decoder, decoder->private_->client_data)) {
+		case FLAC__OGG_DECODER_ASPECT_READ_STATUS_OK:
+			return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+		/* we don't really have a way to handle lost sync via read
+		 * callback so we'll let it pass and let the underlying
+		 * FLAC decoder catch the error
+		 */
+		case FLAC__OGG_DECODER_ASPECT_READ_STATUS_LOST_SYNC:
+			return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+		case FLAC__OGG_DECODER_ASPECT_READ_STATUS_END_OF_STREAM:
+			return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+		case FLAC__OGG_DECODER_ASPECT_READ_STATUS_NOT_FLAC:
+		case FLAC__OGG_DECODER_ASPECT_READ_STATUS_UNSUPPORTED_MAPPING_VERSION:
+		case FLAC__OGG_DECODER_ASPECT_READ_STATUS_ABORT:
+		case FLAC__OGG_DECODER_ASPECT_READ_STATUS_ERROR:
+		case FLAC__OGG_DECODER_ASPECT_READ_STATUS_MEMORY_ALLOCATION_ERROR:
+			return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+		default:
+			FLAC__ASSERT(0);
+			/* double protection */
+			return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+	}
+}
+
+FLAC__OggDecoderAspectReadStatus read_callback_proxy_(const void *void_decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
+{
+	FLAC__StreamDecoder *decoder = (FLAC__StreamDecoder*)void_decoder;
+
+	switch(decoder->private_->read_callback(decoder, buffer, bytes, client_data)) {
+		case FLAC__STREAM_DECODER_READ_STATUS_CONTINUE:
+			return FLAC__OGG_DECODER_ASPECT_READ_STATUS_OK;
+		case FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM:
+			return FLAC__OGG_DECODER_ASPECT_READ_STATUS_END_OF_STREAM;
+		case FLAC__STREAM_DECODER_READ_STATUS_ABORT:
+			return FLAC__OGG_DECODER_ASPECT_READ_STATUS_ABORT;
+		default:
+			/* double protection: */
+			FLAC__ASSERT(0);
+			return FLAC__OGG_DECODER_ASPECT_READ_STATUS_ABORT;
+	}
+}
+#endif
+
+FLAC__StreamDecoderWriteStatus write_audio_frame_to_client_(FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[])
+{
+	if(decoder->private_->is_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 = decoder->private_->target_sample;
+
+		FLAC__ASSERT(frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER);
+
+#if FLAC__HAS_OGG
+		decoder->private_->got_a_frame = true;
+#endif
+		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 */
+			decoder->private_->is_seeking = false;
+			/* 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;
+				decoder->private_->last_frame.header.blocksize -= delta;
+				decoder->private_->last_frame.header.number.sample_number += (FLAC__uint64)delta;
+				/* write the relevant samples */
+				return decoder->private_->write_callback(decoder, &decoder->private_->last_frame, newbuffer, decoder->private_->client_data);
+			}
+			else {
+				/* write the relevant samples */
+				return decoder->private_->write_callback(decoder, frame, buffer, decoder->private_->client_data);
+			}
+		}
+		else {
+			return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+		}
+	}
+	else {
+		/*
+		 * If we never got STREAMINFO, turn off MD5 checking to save
+		 * cycles since we don't have a sum to compare to anyway
+		 */
+		if(!decoder->private_->has_stream_info)
+			decoder->private_->do_md5_checking = false;
+		if(decoder->private_->do_md5_checking) {
+			if(!FLAC__MD5Accumulate(&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 decoder->private_->write_callback(decoder, frame, buffer, decoder->private_->client_data);
+	}
+}
+
+void send_error_to_client_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status)
+{
+	if(!decoder->private_->is_seeking)
+		decoder->private_->error_callback(decoder, status, decoder->private_->client_data);
+	else if(status == FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM)
+		decoder->private_->unparseable_frame_count++;
+}
+
+FLAC__bool seek_to_absolute_sample_(FLAC__StreamDecoder *decoder, FLAC__uint64 stream_length, FLAC__uint64 target_sample)
+{
+	FLAC__uint64 first_frame_offset = decoder->private_->first_frame_offset, lower_bound, upper_bound, lower_bound_sample, upper_bound_sample, this_frame_sample;
+	FLAC__int64 pos = -1;
+	int i;
+	unsigned approx_bytes_per_frame;
+	FLAC__bool first_seek = true;
+	const FLAC__uint64 total_samples = FLAC__stream_decoder_get_total_samples(decoder);
+	const unsigned min_blocksize = decoder->private_->stream_info.data.stream_info.min_blocksize;
+	const unsigned max_blocksize = decoder->private_->stream_info.data.stream_info.max_blocksize;
+	const unsigned max_framesize = decoder->private_->stream_info.data.stream_info.max_framesize;
+	const unsigned min_framesize = decoder->private_->stream_info.data.stream_info.min_framesize;
+	/* take these from the current frame in case they've changed mid-stream */
+	unsigned channels = FLAC__stream_decoder_get_channels(decoder);
+	unsigned bps = FLAC__stream_decoder_get_bits_per_sample(decoder);
+	const FLAC__StreamMetadata_SeekTable *seek_table = decoder->private_->has_seek_table? &decoder->private_->seek_table.data.seek_table : 0;
+
+	/* use values from stream info if we didn't decode a frame */
+	if(channels == 0)
+		channels = decoder->private_->stream_info.data.stream_info.channels;
+	if(bps == 0)
+		bps = decoder->private_->stream_info.data.stream_info.bits_per_sample;
+
+	/* we are just guessing here */
+	if(max_framesize > 0)
+		approx_bytes_per_frame = (max_framesize + min_framesize) / 2 + 1;
+	/*
+	 * 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 = 4096 * channels * bps/8 + 64;
+
+	/*
+	 * 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 frame and end of the stream.
+	 */
+	lower_bound = first_frame_offset;
+	lower_bound_sample = 0;
+	upper_bound = stream_length;
+	upper_bound_sample = total_samples > 0 ? total_samples : target_sample /*estimate it*/;
+
+	/*
+	 * 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.
+	 *
+	 * Note: to protect against invalid seek tables we will ignore points
+	 * that have frame_samples==0 or sample_number>=total_samples
+	 */
+	if(seek_table) {
+		FLAC__uint64 new_lower_bound = lower_bound;
+		FLAC__uint64 new_upper_bound = upper_bound;
+		FLAC__uint64 new_lower_bound_sample = lower_bound_sample;
+		FLAC__uint64 new_upper_bound_sample = upper_bound_sample;
+
+		/* find the closest seek point <= target_sample, if it exists */
+		for(i = (int)seek_table->num_points - 1; i >= 0; i--) {
+			if(
+				seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER &&
+				seek_table->points[i].frame_samples > 0 && /* defense against bad seekpoints */
+				(total_samples <= 0 || seek_table->points[i].sample_number < total_samples) && /* defense against bad seekpoints */
+				seek_table->points[i].sample_number <= target_sample
+			)
+				break;
+		}
+		if(i >= 0) { /* i.e. we found a suitable seek point... */
+			new_lower_bound = first_frame_offset + seek_table->points[i].stream_offset;
+			new_lower_bound_sample = seek_table->points[i].sample_number;
+		}
+
+		/* find the closest seek point > target_sample, if it exists */
+		for(i = 0; i < (int)seek_table->num_points; i++) {
+			if(
+				seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER &&
+				seek_table->points[i].frame_samples > 0 && /* defense against bad seekpoints */
+				(total_samples <= 0 || seek_table->points[i].sample_number < total_samples) && /* defense against bad seekpoints */
+				seek_table->points[i].sample_number > target_sample
+			)
+				break;
+		}
+		if(i < (int)seek_table->num_points) { /* i.e. we found a suitable seek point... */
+			new_upper_bound = first_frame_offset + seek_table->points[i].stream_offset;
+			new_upper_bound_sample = seek_table->points[i].sample_number;
+		}
+		/* final protection against unsorted seek tables; keep original values if bogus */
+		if(new_upper_bound >= new_lower_bound) {
+			lower_bound = new_lower_bound;
+			upper_bound = new_upper_bound;
+			lower_bound_sample = new_lower_bound_sample;
+			upper_bound_sample = new_upper_bound_sample;
+		}
+	}
+
+	FLAC__ASSERT(upper_bound_sample >= lower_bound_sample);
+	/* there are 2 insidious ways that the following equality occurs, which
+	 * we need to fix:
+	 *  1) total_samples is 0 (unknown) and target_sample is 0
+	 *  2) total_samples is 0 (unknown) and target_sample happens to be
+	 *     exactly equal to the last seek point in the seek table; this
+	 *     means there is no seek point above it, and upper_bound_samples
+	 *     remains equal to the estimate (of target_samples) we made above
+	 * in either case it does not hurt to move upper_bound_sample up by 1
+	 */
+	if(upper_bound_sample == lower_bound_sample)
+		upper_bound_sample++;
+
+	decoder->private_->target_sample = target_sample;
+	while(1) {
+		/* check if the bounds are still ok */
+		if (lower_bound_sample >= upper_bound_sample || lower_bound > upper_bound) {
+			decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+			return false;
+		}
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+		pos = (FLAC__int64)lower_bound + (FLAC__int64)((FLAC__double)(target_sample - lower_bound_sample) / (FLAC__double)(upper_bound_sample - lower_bound_sample) * (FLAC__double)(upper_bound - lower_bound)) - approx_bytes_per_frame;
+#else
+		/* a little less accurate: */
+		if(upper_bound - lower_bound < 0xffffffff)
+			pos = (FLAC__int64)lower_bound + (FLAC__int64)(((target_sample - lower_bound_sample) * (upper_bound - lower_bound)) / (upper_bound_sample - lower_bound_sample)) - approx_bytes_per_frame;
+		else /* @@@ WATCHOUT, ~2TB limit */
+			pos = (FLAC__int64)lower_bound + (FLAC__int64)((((target_sample - lower_bound_sample)>>8) * ((upper_bound - lower_bound)>>8)) / ((upper_bound_sample - lower_bound_sample)>>16)) - approx_bytes_per_frame;
+#endif
+		if(pos >= (FLAC__int64)upper_bound)
+			pos = (FLAC__int64)upper_bound - 1;
+		if(pos < (FLAC__int64)lower_bound)
+			pos = (FLAC__int64)lower_bound;
+		if(decoder->private_->seek_callback(decoder, (FLAC__uint64)pos, decoder->private_->client_data) != FLAC__STREAM_DECODER_SEEK_STATUS_OK) {
+			decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+			return false;
+		}
+		if(!FLAC__stream_decoder_flush(decoder)) {
+			/* above call sets the state for us */
+			return false;
+		}
+		/* Now we need to get a frame.  First we need to reset our
+		 * unparseable_frame_count; if we get too many unparseable
+		 * frames in a row, the read callback will return
+		 * FLAC__STREAM_DECODER_READ_STATUS_ABORT, causing
+		 * FLAC__stream_decoder_process_single() to return false.
+		 */
+		decoder->private_->unparseable_frame_count = 0;
+		if(!FLAC__stream_decoder_process_single(decoder)) {
+			decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+			return false;
+		}
+		/* our write callback will change the state when it gets to the target frame */
+		/* actually, we could have got_a_frame if our decoder is at FLAC__STREAM_DECODER_END_OF_STREAM so we need to check for that also */
+#if 0
+		/*@@@@@@ used to be the following; not clear if the check for end of stream is needed anymore */
+		if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_SEEKING && decoder->protected_->state != FLAC__STREAM_DECODER_END_OF_STREAM)
+			break;
+#endif
+		if(!decoder->private_->is_seeking)
+			break;
+
+		FLAC__ASSERT(decoder->private_->last_frame.header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER);
+		this_frame_sample = decoder->private_->last_frame.header.number.sample_number;
+
+		if (0 == decoder->private_->samples_decoded || (this_frame_sample + decoder->private_->last_frame.header.blocksize >= upper_bound_sample && !first_seek)) {
+			if (pos == (FLAC__int64)lower_bound) {
+				/* can't move back any more than the first frame, something is fatally wrong */
+				decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+				return false;
+			}
+			/* our last move backwards wasn't big enough, try again */
+			approx_bytes_per_frame = approx_bytes_per_frame? approx_bytes_per_frame * 2 : 16;
+			continue;
+		}
+		/* allow one seek over upper bound, so we can get a correct upper_bound_sample for streams with unknown total_samples */
+		first_seek = false;
+
+		/* make sure we are not seeking in corrupted stream */
+		if (this_frame_sample < lower_bound_sample) {
+			decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+			return false;
+		}
+
+		/* we need to narrow the search */
+		if(target_sample < this_frame_sample) {
+			upper_bound_sample = this_frame_sample + decoder->private_->last_frame.header.blocksize;
+/*@@@@@@ what will decode position be if at end of stream? */
+			if(!FLAC__stream_decoder_get_decode_position(decoder, &upper_bound)) {
+				decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+				return false;
+			}
+			approx_bytes_per_frame = (unsigned)(2 * (upper_bound - pos) / 3 + 16);
+		}
+		else { /* target_sample >= this_frame_sample + this frame's blocksize */
+			lower_bound_sample = this_frame_sample + decoder->private_->last_frame.header.blocksize;
+			if(!FLAC__stream_decoder_get_decode_position(decoder, &lower_bound)) {
+				decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+				return false;
+			}
+			approx_bytes_per_frame = (unsigned)(2 * (lower_bound - pos) / 3 + 16);
+		}
+	}
+
+	return true;
+}
+
+#if FLAC__HAS_OGG
+FLAC__bool seek_to_absolute_sample_ogg_(FLAC__StreamDecoder *decoder, FLAC__uint64 stream_length, FLAC__uint64 target_sample)
+{
+	FLAC__uint64 left_pos = 0, right_pos = stream_length;
+	FLAC__uint64 left_sample = 0, right_sample = FLAC__stream_decoder_get_total_samples(decoder);
+	FLAC__uint64 this_frame_sample = (FLAC__uint64)0 - 1;
+	FLAC__uint64 pos = 0; /* only initialized to avoid compiler warning */
+	FLAC__bool did_a_seek;
+	unsigned iteration = 0;
+
+	/* In the first iterations, we will calculate the target byte position
+	 * by the distance from the target sample to left_sample and
+	 * right_sample (let's call it "proportional search").  After that, we
+	 * will switch to binary search.
+	 */
+	unsigned BINARY_SEARCH_AFTER_ITERATION = 2;
+
+	/* We will switch to a linear search once our current sample is less
+	 * than this number of samples ahead of the target sample
+	 */
+	static const FLAC__uint64 LINEAR_SEARCH_WITHIN_SAMPLES = FLAC__MAX_BLOCK_SIZE * 2;
+
+	/* If the total number of samples is unknown, use a large value, and
+	 * force binary search immediately.
+	 */
+	if(right_sample == 0) {
+		right_sample = (FLAC__uint64)(-1);
+		BINARY_SEARCH_AFTER_ITERATION = 0;
+	}
+
+	decoder->private_->target_sample = target_sample;
+	for( ; ; iteration++) {
+		if (iteration == 0 || this_frame_sample > target_sample || target_sample - this_frame_sample > LINEAR_SEARCH_WITHIN_SAMPLES) {
+			if (iteration >= BINARY_SEARCH_AFTER_ITERATION) {
+				pos = (right_pos + left_pos) / 2;
+			}
+			else {
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+				pos = (FLAC__uint64)((FLAC__double)(target_sample - left_sample) / (FLAC__double)(right_sample - left_sample) * (FLAC__double)(right_pos - left_pos));
+#else
+				/* a little less accurate: */
+				if ((target_sample-left_sample <= 0xffffffff) && (right_pos-left_pos <= 0xffffffff))
+					pos = (FLAC__int64)(((target_sample-left_sample) * (right_pos-left_pos)) / (right_sample-left_sample));
+				else /* @@@ WATCHOUT, ~2TB limit */
+					pos = (FLAC__int64)((((target_sample-left_sample)>>8) * ((right_pos-left_pos)>>8)) / ((right_sample-left_sample)>>16));
+#endif
+				/* @@@ TODO: might want to limit pos to some distance
+				 * before EOF, to make sure we land before the last frame,
+				 * thereby getting a this_frame_sample and so having a better
+				 * estimate.
+				 */
+			}
+
+			/* physical seek */
+			if(decoder->private_->seek_callback((FLAC__StreamDecoder*)decoder, (FLAC__uint64)pos, decoder->private_->client_data) != FLAC__STREAM_DECODER_SEEK_STATUS_OK) {
+				decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+				return false;
+			}
+			if(!FLAC__stream_decoder_flush(decoder)) {
+				/* above call sets the state for us */
+				return false;
+			}
+			did_a_seek = true;
+		}
+		else
+			did_a_seek = false;
+
+		decoder->private_->got_a_frame = false;
+		if(!FLAC__stream_decoder_process_single(decoder)) {
+			decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+			return false;
+		}
+		if(!decoder->private_->got_a_frame) {
+			if(did_a_seek) {
+				/* this can happen if we seek to a point after the last frame; we drop
+				 * to binary search right away in this case to avoid any wasted
+				 * iterations of proportional search.
+				 */
+				right_pos = pos;
+				BINARY_SEARCH_AFTER_ITERATION = 0;
+			}
+			else {
+				/* this can probably only happen if total_samples is unknown and the
+				 * target_sample is past the end of the stream
+				 */
+				decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+				return false;
+			}
+		}
+		/* our write callback will change the state when it gets to the target frame */
+		else if(!decoder->private_->is_seeking) {
+			break;
+		}
+		else {
+			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 (did_a_seek) {
+				if (this_frame_sample <= target_sample) {
+					/* The 'equal' case should not happen, since
+					 * FLAC__stream_decoder_process_single()
+					 * should recognize that it has hit the
+					 * target sample and we would exit through
+					 * the 'break' above.
+					 */
+					FLAC__ASSERT(this_frame_sample != target_sample);
+
+					left_sample = this_frame_sample;
+					/* sanity check to avoid infinite loop */
+					if (left_pos == pos) {
+						decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+						return false;
+					}
+					left_pos = pos;
+				}
+				else if(this_frame_sample > target_sample) {
+					right_sample = this_frame_sample;
+					/* sanity check to avoid infinite loop */
+					if (right_pos == pos) {
+						decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+						return false;
+					}
+					right_pos = pos;
+				}
+			}
+		}
+	}
+
+	return true;
+}
+#endif
+
+FLAC__StreamDecoderReadStatus file_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
+{
+	(void)client_data;
+
+	if(*bytes > 0) {
+		*bytes = fread(buffer, sizeof(FLAC__byte), *bytes, decoder->private_->file);
+		if(ferror(decoder->private_->file))
+			return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+		else if(*bytes == 0)
+			return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+		else
+			return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+	}
+	else
+		return FLAC__STREAM_DECODER_READ_STATUS_ABORT; /* abort to avoid a deadlock */
+}
+
+FLAC__StreamDecoderSeekStatus file_seek_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data)
+{
+	(void)client_data;
+
+	if(decoder->private_->file == stdin)
+		return FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED;
+	else if(fseeko(decoder->private_->file, (FLAC__off_t)absolute_byte_offset, SEEK_SET) < 0)
+		return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
+	else
+		return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
+}
+
+FLAC__StreamDecoderTellStatus file_tell_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
+{
+	FLAC__off_t pos;
+	(void)client_data;
+
+	if(decoder->private_->file == stdin)
+		return FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED;
+	else if((pos = ftello(decoder->private_->file)) < 0)
+		return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
+	else {
+		*absolute_byte_offset = (FLAC__uint64)pos;
+		return FLAC__STREAM_DECODER_TELL_STATUS_OK;
+	}
+}
+
+FLAC__StreamDecoderLengthStatus file_length_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data)
+{
+	struct flac_stat_s filestats;
+	(void)client_data;
+
+	if(decoder->private_->file == stdin)
+		return FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED;
+	else if(flac_fstat(fileno(decoder->private_->file), &filestats) != 0)
+		return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
+	else {
+		*stream_length = (FLAC__uint64)filestats.st_size;
+		return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
+	}
+}
+
+FLAC__bool file_eof_callback_(const FLAC__StreamDecoder *decoder, void *client_data)
+{
+	(void)client_data;
+
+	return feof(decoder->private_->file)? true : false;
 }
--- a/sys/src/cmd/audio/libFLAC/stream_encoder.c
+++ b/sys/src/cmd/audio/libFLAC/stream_encoder.c
@@ -1,5 +1,6 @@
 /* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2000,2001,2002,2003,2004  Josh Coalson
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2014  Xiph.Org Foundation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -29,14 +30,20 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
 #include <limits.h>
 #include <stdio.h>
 #include <stdlib.h> /* for malloc() */
 #include <string.h> /* for memcpy() */
+#include <sys/types.h> /* for off_t */
+#include "share/compat.h"
 #include "FLAC/assert.h"
 #include "FLAC/stream_decoder.h"
 #include "protected/stream_encoder.h"
-#include "private/bitbuffer.h"
+#include "private/bitwriter.h"
 #include "private/bitmath.h"
 #include "private/crc.h"
 #include "private/cpu.h"
@@ -45,21 +52,30 @@
 #include "private/lpc.h"
 #include "private/md5.h"
 #include "private/memory.h"
+#include "private/macros.h"
+#if FLAC__HAS_OGG
+#include "private/ogg_helper.h"
+#include "private/ogg_mapping.h"
+#endif
+#include "private/stream_encoder.h"
 #include "private/stream_encoder_framing.h"
+#include "private/window.h"
+#include "share/alloc.h"
+#include "share/private.h"
 
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
 
-#ifdef min
-#undef min
-#endif
-#define min(x,y) ((x)<(y)?(x):(y))
+/* Exact Rice codeword length calculation is off by default.  The simple
+ * (and fast) estimation (of how many bits a residual value will be
+ * encoded with) in this encoder is very good, almost always yielding
+ * compression within 0.1% of exact calculation.
+ */
+#undef EXACT_RICE_BITS_CALCULATION
+/* Rice parameter searching is off by default.  The simple (and fast)
+ * parameter estimation in this encoder is very good, almost always
+ * yielding compression within 0.1% of the optimal parameters.
+ */
+#undef ENABLE_RICE_PARAMETER_SEARCH
 
-#ifdef max
-#undef max
-#endif
-#define max(x,y) ((x)>(y)?(x):(y))
 
 typedef struct {
 	FLAC__int32 *data[FLAC__MAX_CHANNELS];
@@ -79,6 +95,32 @@
 	ENCODER_IN_AUDIO = 2
 } EncoderStateHint;
 
+static struct CompressionLevels {
+	FLAC__bool do_mid_side_stereo;
+	FLAC__bool loose_mid_side_stereo;
+	unsigned max_lpc_order;
+	unsigned qlp_coeff_precision;
+	FLAC__bool do_qlp_coeff_prec_search;
+	FLAC__bool do_escape_coding;
+	FLAC__bool do_exhaustive_model_search;
+	unsigned min_residual_partition_order;
+	unsigned max_residual_partition_order;
+	unsigned rice_parameter_search_dist;
+	const char *apodization;
+} compression_levels_[] = {
+	{ false, false,  0, 0, false, false, false, 0, 3, 0, "tukey(5e-1)" },
+	{ true , true ,  0, 0, false, false, false, 0, 3, 0, "tukey(5e-1)" },
+	{ true , false,  0, 0, false, false, false, 0, 3, 0, "tukey(5e-1)" },
+	{ false, false,  6, 0, false, false, false, 0, 4, 0, "tukey(5e-1)" },
+	{ true , true ,  8, 0, false, false, false, 0, 4, 0, "tukey(5e-1)" },
+	{ true , false,  8, 0, false, false, false, 0, 5, 0, "tukey(5e-1)" },
+	{ true , false,  8, 0, false, false, false, 0, 6, 0, "tukey(5e-1);partial_tukey(2)" },
+	{ true , false, 12, 0, false, false, false, 0, 6, 0, "tukey(5e-1);partial_tukey(2)" },
+	{ true , false, 12, 0, false, false, false, 0, 6, 0, "tukey(5e-1);partial_tukey(2);punchout_tukey(3)" }
+	/* here we use locale-independent 5e-1 instead of 0.5 or 0,5 */
+};
+
+
 /***********************************************************************
  *
  * Private class method prototypes
@@ -87,20 +129,23 @@
 
 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 resize_buffers_(FLAC__StreamEncoder *encoder, unsigned new_blocksize);
+static FLAC__bool write_bitbuffer_(FLAC__StreamEncoder *encoder, unsigned samples, FLAC__bool is_last_block);
+static FLAC__StreamEncoderWriteStatus write_frame_(FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples, FLAC__bool is_last_block);
+static void update_metadata_(const FLAC__StreamEncoder *encoder);
+#if FLAC__HAS_OGG
+static void update_ogg_metadata_(FLAC__StreamEncoder *encoder);
+#endif
+static FLAC__bool process_frame_(FLAC__StreamEncoder *encoder, FLAC__bool is_fractional_block, FLAC__bool is_last_block);
+static FLAC__bool process_subframes_(FLAC__StreamEncoder *encoder, FLAC__bool is_fractional_block);
 
 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],
@@ -110,14 +155,16 @@
 
 static FLAC__bool add_subframe_(
 	FLAC__StreamEncoder *encoder,
-	const FLAC__FrameHeader *frame_header,
+	unsigned blocksize,
 	unsigned subframe_bps,
 	const FLAC__Subframe *subframe,
-	FLAC__BitBuffer *frame
+	FLAC__BitWriter *frame
 );
 
 static unsigned evaluate_constant_subframe_(
+	FLAC__StreamEncoder *encoder,
 	const FLAC__int32 signal,
+	unsigned blocksize,
 	unsigned subframe_bps,
 	FLAC__Subframe *subframe
 );
@@ -126,7 +173,6 @@
 	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,
@@ -133,9 +179,9 @@
 	unsigned subframe_bps,
 	unsigned order,
 	unsigned rice_parameter,
+	unsigned rice_parameter_limit,
 	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,
@@ -142,11 +188,11 @@
 	FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents
 );
 
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
 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[],
@@ -155,16 +201,18 @@
 	unsigned order,
 	unsigned qlp_coeff_precision,
 	unsigned rice_parameter,
+	unsigned rice_parameter_limit,
 	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
 );
+#endif
 
 static unsigned evaluate_verbatim_subframe_(
+	FLAC__StreamEncoder *encoder,
 	const FLAC__int32 signal[],
 	unsigned blocksize,
 	unsigned subframe_bps,
@@ -174,27 +222,28 @@
 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 rice_parameter_limit,
 	unsigned min_partition_order,
 	unsigned max_partition_order,
-	FLAC__bool precompute_partition_sums,
+	unsigned bps,
 	FLAC__bool do_escape_coding,
 	unsigned rice_parameter_search_dist,
-	FLAC__EntropyCodingMethod_PartitionedRice *best_partitioned_rice
+	FLAC__EntropyCodingMethod *best_ecm
 );
 
 static void precompute_partition_info_sums_(
-	const FLAC__uint32 abs_residual[],
+	const FLAC__int32 residual[],
 	FLAC__uint64 abs_residual_partition_sums[],
 	unsigned residual_samples,
 	unsigned predictor_order,
 	unsigned min_partition_order,
-	unsigned max_partition_order
+	unsigned max_partition_order,
+	unsigned bps
 );
 
 static void precompute_partition_info_escapes_(
@@ -206,26 +255,16 @@
 	unsigned max_partition_order
 );
 
-#ifdef DONT_ESTIMATE_RICE_BITS
 static FLAC__bool set_partitioned_rice_(
-	const FLAC__uint32 abs_residual[],
+#ifdef EXACT_RICE_BITS_CALCULATION
 	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[],
+#endif
 	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_limit,
 	const unsigned rice_parameter_search_dist,
 	const unsigned partition_order,
 	const FLAC__bool search_for_escapes,
@@ -232,33 +271,7 @@
 	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: */
@@ -278,33 +291,18 @@
 	unsigned wide_samples
 );
 
-static FLAC__StreamDecoderReadStatus verify_read_callback_(
-	const FLAC__StreamDecoder *decoder,
-	FLAC__byte buffer[],
-	unsigned *bytes,
-	void *client_data
-);
+static FLAC__StreamDecoderReadStatus verify_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *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);
 
-static FLAC__StreamDecoderWriteStatus verify_write_callback_(
-	const FLAC__StreamDecoder *decoder,
-	const FLAC__Frame *frame,
-	const FLAC__int32 * const buffer[],
-	void *client_data
-);
+static FLAC__StreamEncoderReadStatus file_read_callback_(const FLAC__StreamEncoder *encoder, FLAC__byte buffer[], size_t *bytes, void *client_data);
+static FLAC__StreamEncoderSeekStatus file_seek_callback_(const FLAC__StreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data);
+static FLAC__StreamEncoderTellStatus file_tell_callback_(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data);
+static FLAC__StreamEncoderWriteStatus file_write_callback_(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame, void *client_data);
+static FILE *get_binary_stdout_(void);
 
-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
@@ -315,8 +313,12 @@
 	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) */
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+	FLAC__real *real_signal[FLAC__MAX_CHANNELS];      /* (@@@ currently unused) the floating-point version of the input signal */
+	FLAC__real *real_signal_mid_side[2];              /* (@@@ currently unused) the floating-point version of the mid-side input signal (stereo only) */
+	FLAC__real *window[FLAC__MAX_APODIZATION_FUNCTIONS]; /* the pre-computed floating-point window for each apodization function */
+	FLAC__real *windowed_signal;                      /* the integer_signal[] * current window[] */
+#endif
 	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 */
@@ -329,46 +331,69 @@
 	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[FLAC__MAX_CHANNELS];       /* index (0 or 1) into 2nd dimension of 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 */
+	FLAC__BitWriter *frame;                           /* the current frame being worked on */
 	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;
+	FLAC__StreamMetadata streaminfo;                  /* scratchpad for STREAMINFO as it is built */
+	FLAC__StreamMetadata_SeekTable *seek_table;       /* pointer into encoder->protected_->metadata_ where the seek table is */
 	unsigned current_sample_number;
 	unsigned current_frame_number;
-	struct FLAC__MD5Context md5context;
+	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_precompute_partition_info_sums)(const FLAC__int32 residual[], FLAC__uint64 abs_residual_partition_sums[], unsigned residual_samples, unsigned predictor_order, unsigned min_partition_order, unsigned max_partition_order, unsigned bps);
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+	unsigned (*local_fixed_compute_best_predictor)(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+	unsigned (*local_fixed_compute_best_predictor_wide)(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+#else
+	unsigned (*local_fixed_compute_best_predictor)(const FLAC__int32 data[], unsigned data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+	unsigned (*local_fixed_compute_best_predictor_wide)(const FLAC__int32 data[], unsigned data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+#endif
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
 	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[]);
+	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[]);
+#endif
 	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;
+#if FLAC__HAS_OGG
+	FLAC__bool is_ogg;
+#endif
+	FLAC__StreamEncoderReadCallback read_callback; /* currently only needed for Ogg FLAC */
+	FLAC__StreamEncoderSeekCallback seek_callback;
+	FLAC__StreamEncoderTellCallback tell_callback;
 	FLAC__StreamEncoderWriteCallback write_callback;
 	FLAC__StreamEncoderMetadataCallback metadata_callback;
+	FLAC__StreamEncoderProgressCallback progress_callback;
 	void *client_data;
+	unsigned first_seekpoint_to_check;
+	FILE *file;                            /* only used when encoding to a file */
+	FLAC__uint64 bytes_written;
+	FLAC__uint64 samples_written;
+	unsigned frames_written;
+	unsigned total_frames_estimate;
 	/* 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];
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+	FLAC__real *real_signal_unaligned[FLAC__MAX_CHANNELS]; /* (@@@ currently unused) */
+	FLAC__real *real_signal_mid_side_unaligned[2]; /* (@@@ currently unused) */
+	FLAC__real *window_unaligned[FLAC__MAX_APODIZATION_FUNCTIONS];
+	FLAC__real *windowed_signal_unaligned;
+#endif
 	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;
 	/*
@@ -375,7 +400,9 @@
 	 * These fields have been moved here from private function local
 	 * declarations merely to save stack space during encoding.
 	 */
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
 	FLAC__real lp_coeff[FLAC__MAX_LPC_ORDER][FLAC__MAX_LPC_ORDER]; /* from process_subframe_() */
+#endif
 	FLAC__EntropyCodingMethod_PartitionedRiceContents partitioned_rice_contents_extra[2]; /* from find_best_partition_order_() */
 	/*
 	 * The data for the verify section
@@ -406,36 +433,70 @@
 
 FLAC_API const char * const FLAC__StreamEncoderStateString[] = {
 	"FLAC__STREAM_ENCODER_OK",
+	"FLAC__STREAM_ENCODER_UNINITIALIZED",
+	"FLAC__STREAM_ENCODER_OGG_ERROR",
 	"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_CLIENT_ERROR",
+	"FLAC__STREAM_ENCODER_IO_ERROR",
 	"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__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR"
 };
 
+FLAC_API const char * const FLAC__StreamEncoderInitStatusString[] = {
+	"FLAC__STREAM_ENCODER_INIT_STATUS_OK",
+	"FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR",
+	"FLAC__STREAM_ENCODER_INIT_STATUS_UNSUPPORTED_CONTAINER",
+	"FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_CALLBACKS",
+	"FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_NUMBER_OF_CHANNELS",
+	"FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_BITS_PER_SAMPLE",
+	"FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_SAMPLE_RATE",
+	"FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_BLOCK_SIZE",
+	"FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_MAX_LPC_ORDER",
+	"FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_QLP_COEFF_PRECISION",
+	"FLAC__STREAM_ENCODER_INIT_STATUS_BLOCK_SIZE_TOO_SMALL_FOR_LPC_ORDER",
+	"FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE",
+	"FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA",
+	"FLAC__STREAM_ENCODER_INIT_STATUS_ALREADY_INITIALIZED"
+};
+
+FLAC_API const char * const FLAC__StreamEncoderReadStatusString[] = {
+	"FLAC__STREAM_ENCODER_READ_STATUS_CONTINUE",
+	"FLAC__STREAM_ENCODER_READ_STATUS_END_OF_STREAM",
+	"FLAC__STREAM_ENCODER_READ_STATUS_ABORT",
+	"FLAC__STREAM_ENCODER_READ_STATUS_UNSUPPORTED"
+};
+
 FLAC_API const char * const FLAC__StreamEncoderWriteStatusString[] = {
 	"FLAC__STREAM_ENCODER_WRITE_STATUS_OK",
 	"FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR"
 };
 
-FLAC__BitBuffer *FLAC__bitbuffer_new(void);
+FLAC_API const char * const FLAC__StreamEncoderSeekStatusString[] = {
+	"FLAC__STREAM_ENCODER_SEEK_STATUS_OK",
+	"FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR",
+	"FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED"
+};
 
+FLAC_API const char * const FLAC__StreamEncoderTellStatusString[] = {
+	"FLAC__STREAM_ENCODER_TELL_STATUS_OK",
+	"FLAC__STREAM_ENCODER_TELL_STATUS_ERROR",
+	"FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED"
+};
+
+/* Number of samples that will be overread to watch for end of stream.  By
+ * 'overread', we mean that the FLAC__stream_encoder_process*() calls will
+ * always try to read blocksize+1 samples before encoding a block, so that
+ * even if the stream has a total sample count that is an integral multiple
+ * of the blocksize, we will still notice when we are encoding the last
+ * block.  This is needed, for example, to correctly set the end-of-stream
+ * marker in Ogg FLAC.
+ *
+ * WATCHOUT: some parts of the code assert that OVERREAD_ == 1 and there's
+ * not really any reason to change it.
+ */
+static const unsigned OVERREAD_ = 1;
+
 /***********************************************************************
  *
  * Class constructor/destructor
@@ -448,18 +509,18 @@
 
 	FLAC__ASSERT(sizeof(int) >= 4); /* we want to die right away if this is not true */
 
-	encoder = (FLAC__StreamEncoder*)calloc(1, sizeof(FLAC__StreamEncoder));
+	encoder = calloc(1, sizeof(FLAC__StreamEncoder));
 	if(encoder == 0) {
 		return 0;
 	}
 
-	encoder->protected_ = (FLAC__StreamEncoderProtected*)calloc(1, sizeof(FLAC__StreamEncoderProtected));
+	encoder->protected_ = calloc(1, sizeof(FLAC__StreamEncoderProtected));
 	if(encoder->protected_ == 0) {
 		free(encoder);
 		return 0;
 	}
 
-	encoder->private_ = (FLAC__StreamEncoderPrivate*)calloc(1, sizeof(FLAC__StreamEncoderPrivate));
+	encoder->private_ = calloc(1, sizeof(FLAC__StreamEncoderPrivate));
 	if(encoder->private_ == 0) {
 		free(encoder->protected_);
 		free(encoder);
@@ -466,7 +527,7 @@
 		return 0;
 	}
 
-	encoder->private_->frame = FLAC__bitbuffer_new();
+	encoder->private_->frame = FLAC__bitwriter_new();
 	if(encoder->private_->frame == 0) {
 		free(encoder->private_);
 		free(encoder->protected_);
@@ -474,6 +535,8 @@
 		return 0;
 	}
 
+	encoder->private_->file = 0;
+
 	set_defaults_(encoder);
 
 	encoder->private_->is_being_deleted = false;
@@ -515,7 +578,9 @@
 {
 	unsigned i;
 
-	FLAC__ASSERT(0 != encoder);
+	if (encoder == NULL)
+		return ;
+
 	FLAC__ASSERT(0 != encoder->protected_);
 	FLAC__ASSERT(0 != encoder->private_);
 	FLAC__ASSERT(0 != encoder->private_->frame);
@@ -522,7 +587,7 @@
 
 	encoder->private_->is_being_deleted = true;
 
-	FLAC__stream_encoder_finish(encoder);
+	(void)FLAC__stream_encoder_finish(encoder);
 
 	if(0 != encoder->private_->verify.decoder)
 		FLAC__stream_decoder_delete(encoder->private_->verify.decoder);
@@ -538,7 +603,7 @@
 	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);
+	FLAC__bitwriter_delete(encoder->private_->frame);
 	free(encoder->private_);
 	free(encoder->protected_);
 	free(encoder);
@@ -550,53 +615,73 @@
  *
  ***********************************************************************/
 
-FLAC_API FLAC__StreamEncoderState FLAC__stream_encoder_init(FLAC__StreamEncoder *encoder)
+static FLAC__StreamEncoderInitStatus init_stream_internal_(
+	FLAC__StreamEncoder *encoder,
+	FLAC__StreamEncoderReadCallback read_callback,
+	FLAC__StreamEncoderWriteCallback write_callback,
+	FLAC__StreamEncoderSeekCallback seek_callback,
+	FLAC__StreamEncoderTellCallback tell_callback,
+	FLAC__StreamEncoderMetadataCallback metadata_callback,
+	void *client_data,
+	FLAC__bool is_ogg
+)
 {
 	unsigned i;
-	FLAC__bool metadata_has_seektable, metadata_has_vorbis_comment;
+	FLAC__bool metadata_has_seektable, metadata_has_vorbis_comment, metadata_picture_has_type1, metadata_picture_has_type2;
 
 	FLAC__ASSERT(0 != encoder);
 
 	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
-		return encoder->protected_->state = FLAC__STREAM_ENCODER_ALREADY_INITIALIZED;
+		return FLAC__STREAM_ENCODER_INIT_STATUS_ALREADY_INITIALIZED;
 
-	encoder->protected_->state = FLAC__STREAM_ENCODER_OK;
+#if !FLAC__HAS_OGG
+	if(is_ogg)
+		return FLAC__STREAM_ENCODER_INIT_STATUS_UNSUPPORTED_CONTAINER;
+#endif
 
-	if(0 == encoder->private_->write_callback || 0 == encoder->private_->metadata_callback)
-		return encoder->protected_->state = FLAC__STREAM_ENCODER_INVALID_CALLBACK;
+	if(0 == write_callback || (seek_callback && 0 == tell_callback))
+		return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_CALLBACKS;
 
 	if(encoder->protected_->channels == 0 || encoder->protected_->channels > FLAC__MAX_CHANNELS)
-		return encoder->protected_->state = FLAC__STREAM_ENCODER_INVALID_NUMBER_OF_CHANNELS;
+		return FLAC__STREAM_ENCODER_INIT_STATUS_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_->channels != 2) {
+		encoder->protected_->do_mid_side_stereo = false;
+		encoder->protected_->loose_mid_side_stereo = false;
+	}
+	else if(!encoder->protected_->do_mid_side_stereo)
+		encoder->protected_->loose_mid_side_stereo = false;
 
-	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 */
+		encoder->protected_->do_mid_side_stereo = false; /* since we currenty 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;
+		return FLAC__STREAM_ENCODER_INIT_STATUS_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;
+		return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_SAMPLE_RATE;
 
+	if(encoder->protected_->blocksize == 0) {
+		if(encoder->protected_->max_lpc_order == 0)
+			encoder->protected_->blocksize = 1152;
+		else
+			encoder->protected_->blocksize = 4096;
+	}
+
 	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;
+		return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_BLOCK_SIZE;
 
 	if(encoder->protected_->max_lpc_order > FLAC__MAX_LPC_ORDER)
-		return encoder->protected_->state = FLAC__STREAM_ENCODER_INVALID_MAX_LPC_ORDER;
+		return FLAC__STREAM_ENCODER_INIT_STATUS_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;
+		return FLAC__STREAM_ENCODER_INIT_STATUS_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);
+			encoder->protected_->qlp_coeff_precision = flac_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)
@@ -625,36 +710,14 @@
 		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;
+		return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_QLP_COEFF_PRECISION;
 
 	if(encoder->protected_->streamable_subset) {
+		if(!FLAC__format_blocksize_is_subset(encoder->protected_->blocksize, encoder->protected_->sample_rate))
+			return FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE;
+		if(!FLAC__format_sample_rate_is_subset(encoder->protected_->sample_rate))
+			return FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE;
 		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 &&
@@ -661,9 +724,18 @@
 			encoder->protected_->bits_per_sample != 20 &&
 			encoder->protected_->bits_per_sample != 24
 		)
-			return encoder->protected_->state = FLAC__STREAM_ENCODER_NOT_STREAMABLE;
+			return FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE;
 		if(encoder->protected_->max_residual_partition_order > FLAC__SUBSET_MAX_RICE_PARTITION_ORDER)
-			return encoder->protected_->state = FLAC__STREAM_ENCODER_NOT_STREAMABLE;
+			return FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE;
+		if(
+			encoder->protected_->sample_rate <= 48000 &&
+			(
+				encoder->protected_->blocksize > FLAC__SUBSET_MAX_BLOCK_SIZE_48000HZ ||
+				encoder->protected_->max_lpc_order > FLAC__SUBSET_MAX_LPC_ORDER_48000HZ
+			)
+		) {
+			return FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE;
+		}
 	}
 
 	if(encoder->protected_->max_residual_partition_order >= (1u << FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN))
@@ -671,41 +743,103 @@
 	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;
 
+#if FLAC__HAS_OGG
+	/* reorder metadata if necessary to ensure that any VORBIS_COMMENT is the first, according to the mapping spec */
+	if(is_ogg && 0 != encoder->protected_->metadata && encoder->protected_->num_metadata_blocks > 1) {
+		unsigned i1;
+		for(i1 = 1; i1 < encoder->protected_->num_metadata_blocks; i1++) {
+			if(0 != encoder->protected_->metadata[i1] && encoder->protected_->metadata[i1]->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
+				FLAC__StreamMetadata *vc = encoder->protected_->metadata[i1];
+				for( ; i1 > 0; i1--)
+					encoder->protected_->metadata[i1] = encoder->protected_->metadata[i1-1];
+				encoder->protected_->metadata[0] = vc;
+				break;
+			}
+		}
+	}
+#endif
+	/* keep track of any SEEKTABLE block */
+	if(0 != encoder->protected_->metadata && encoder->protected_->num_metadata_blocks > 0) {
+		unsigned i2;
+		for(i2 = 0; i2 < encoder->protected_->num_metadata_blocks; i2++) {
+			if(0 != encoder->protected_->metadata[i2] && encoder->protected_->metadata[i2]->type == FLAC__METADATA_TYPE_SEEKTABLE) {
+				encoder->private_->seek_table = &encoder->protected_->metadata[i2]->data.seek_table;
+				break; /* take only the first one */
+			}
+		}
+	}
+
 	/* validate metadata */
 	if(0 == encoder->protected_->metadata && encoder->protected_->num_metadata_blocks > 0)
-		return encoder->protected_->state = FLAC__STREAM_ENCODER_INVALID_METADATA;
+		return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA;
 	metadata_has_seektable = false;
 	metadata_has_vorbis_comment = false;
+	metadata_picture_has_type1 = false;
+	metadata_picture_has_type2 = 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) {
+		const FLAC__StreamMetadata *m = encoder->protected_->metadata[i];
+		if(m->type == FLAC__METADATA_TYPE_STREAMINFO)
+			return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA;
+		else if(m->type == FLAC__METADATA_TYPE_SEEKTABLE) {
 			if(metadata_has_seektable) /* only one is allowed */
-				return encoder->protected_->state = FLAC__STREAM_ENCODER_INVALID_METADATA;
+				return FLAC__STREAM_ENCODER_INIT_STATUS_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;
+			if(!FLAC__format_seektable_is_legal(&m->data.seek_table))
+				return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA;
 		}
-		else if(encoder->protected_->metadata[i]->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
+		else if(m->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
 			if(metadata_has_vorbis_comment) /* only one is allowed */
-				return encoder->protected_->state = FLAC__STREAM_ENCODER_INVALID_METADATA;
+				return FLAC__STREAM_ENCODER_INIT_STATUS_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;
+		else if(m->type == FLAC__METADATA_TYPE_CUESHEET) {
+			if(!FLAC__format_cuesheet_is_legal(&m->data.cue_sheet, m->data.cue_sheet.is_cd, /*violation=*/0))
+				return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA;
 		}
+		else if(m->type == FLAC__METADATA_TYPE_PICTURE) {
+			if(!FLAC__format_picture_is_legal(&m->data.picture, /*violation=*/0))
+				return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA;
+			if(m->data.picture.type == FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON_STANDARD) {
+				if(metadata_picture_has_type1) /* there should only be 1 per stream */
+					return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA;
+				metadata_picture_has_type1 = true;
+				/* standard icon must be 32x32 pixel PNG */
+				if(
+					m->data.picture.type == FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON_STANDARD &&
+					(
+						(strcmp(m->data.picture.mime_type, "image/png") && strcmp(m->data.picture.mime_type, "-->")) ||
+						m->data.picture.width != 32 ||
+						m->data.picture.height != 32
+					)
+				)
+					return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA;
+			}
+			else if(m->data.picture.type == FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON) {
+				if(metadata_picture_has_type2) /* there should only be 1 per stream */
+					return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA;
+				metadata_picture_has_type2 = true;
+			}
+		}
 	}
 
 	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;
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
 		encoder->private_->real_signal_unaligned[i] = encoder->private_->real_signal[i] = 0;
+#endif
 	}
 	for(i = 0; i < 2; i++) {
 		encoder->private_->integer_signal_mid_side_unaligned[i] = encoder->private_->integer_signal_mid_side[i] = 0;
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
 		encoder->private_->real_signal_mid_side_unaligned[i] = encoder->private_->real_signal_mid_side[i] = 0;
+#endif
 	}
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+	for(i = 0; i < encoder->protected_->num_apodizations; i++)
+		encoder->private_->window_unaligned[i] = encoder->private_->window[i] = 0;
+	encoder->private_->windowed_signal_unaligned = encoder->private_->windowed_signal = 0;
+#endif
 	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;
@@ -716,11 +850,19 @@
 		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);
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+	encoder->private_->loose_mid_side_stereo_frames = (unsigned)((FLAC__double)encoder->protected_->sample_rate * 0.4 / (FLAC__double)encoder->protected_->blocksize + 0.5);
+#else
+	/* 26214 is the approximate fixed-point equivalent to 0.4 (0.4 * 2^16) */
+	/* sample rate can be up to 655350 Hz, and thus use 20 bits, so we do the multiply&divide by hand */
+	FLAC__ASSERT(FLAC__MAX_SAMPLE_RATE <= 655350);
+	FLAC__ASSERT(FLAC__MAX_BLOCK_SIZE <= 65535);
+	FLAC__ASSERT(encoder->protected_->sample_rate <= 655350);
+	FLAC__ASSERT(encoder->protected_->blocksize <= 65535);
+	encoder->private_->loose_mid_side_stereo_frames = (unsigned)FLAC__fixedpoint_trunc((((FLAC__uint64)(encoder->protected_->sample_rate) * (FLAC__uint64)(26214)) << 16) / (encoder->protected_->blocksize<<16) + FLAC__FP_ONE_HALF);
+#endif
 	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;
@@ -728,7 +870,7 @@
 	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_order = (encoder->protected_->bits_per_sample + FLAC__bitmath_ilog2(flac_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 */
 
 	/*
@@ -736,19 +878,25 @@
 	 */
 	FLAC__cpu_info(&encoder->private_->cpuinfo);
 	/* first default to the non-asm routines */
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
 	encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation;
+#endif
+	encoder->private_->local_precompute_partition_info_sums = precompute_partition_info_sums_;
 	encoder->private_->local_fixed_compute_best_predictor = FLAC__fixed_compute_best_predictor;
+	encoder->private_->local_fixed_compute_best_predictor_wide = FLAC__fixed_compute_best_predictor_wide;
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
 	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;
+#endif
 	/* now override with asm where appropriate */
-#ifndef FLAC__NO_ASM
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+# ifndef FLAC__NO_ASM
 	if(encoder->private_->cpuinfo.use_asm) {
-#ifdef FLAC__CPU_IA32
+#  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) {
+#   ifdef FLAC__HAS_NASM
+		if(encoder->private_->cpuinfo.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)
@@ -755,18 +903,16 @@
 				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 if(encoder->protected_->max_lpc_order < 16)
+				encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_16;
 			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_64bit = FLAC__lpc_compute_residual_from_qlp_coefficients_wide_asm_ia32; /* OPT_IA32: was really necessary for GCC < 4.9 */
+		if(encoder->private_->cpuinfo.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;
 		}
@@ -774,25 +920,166 @@
 			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
+
+		if(encoder->private_->cpuinfo.ia32.mmx && encoder->private_->cpuinfo.ia32.cmov)
+			encoder->private_->local_fixed_compute_best_predictor = FLAC__fixed_compute_best_predictor_asm_ia32_mmx_cmov;
+#   endif /* FLAC__HAS_NASM */
+#   ifdef FLAC__HAS_X86INTRIN
+#    if defined FLAC__SSE_SUPPORTED
+		if(encoder->private_->cpuinfo.ia32.sse) {
+			if(encoder->protected_->max_lpc_order < 4)
+				encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_4;
+			else if(encoder->protected_->max_lpc_order < 8)
+				encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_8;
+			else if(encoder->protected_->max_lpc_order < 12)
+				encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_12;
+			else if(encoder->protected_->max_lpc_order < 16)
+				encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_16;
+			else
+				encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation;
+		}
+#    endif
+
+#    ifdef FLAC__SSE2_SUPPORTED
+		if(encoder->private_->cpuinfo.ia32.sse2) {
+			encoder->private_->local_lpc_compute_residual_from_qlp_coefficients       = FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_sse2;
+			encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit = FLAC__lpc_compute_residual_from_qlp_coefficients_16_intrin_sse2;
+		}
+#    endif
+#    ifdef FLAC__SSE4_1_SUPPORTED
+		if(encoder->private_->cpuinfo.ia32.sse41) {
+			encoder->private_->local_lpc_compute_residual_from_qlp_coefficients       = FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_sse41;
+			encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_64bit = FLAC__lpc_compute_residual_from_qlp_coefficients_wide_intrin_sse41;
+		}
+#    endif
+#    ifdef FLAC__AVX2_SUPPORTED
+		if(encoder->private_->cpuinfo.ia32.avx2) {
+			encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit = FLAC__lpc_compute_residual_from_qlp_coefficients_16_intrin_avx2;
+			encoder->private_->local_lpc_compute_residual_from_qlp_coefficients       = FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_avx2;
+			encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_64bit = FLAC__lpc_compute_residual_from_qlp_coefficients_wide_intrin_avx2;
+		}
+#    endif
+
+#    ifdef FLAC__SSE2_SUPPORTED
+		if (encoder->private_->cpuinfo.ia32.sse2) {
+			encoder->private_->local_fixed_compute_best_predictor      = FLAC__fixed_compute_best_predictor_intrin_sse2;
+			encoder->private_->local_fixed_compute_best_predictor_wide = FLAC__fixed_compute_best_predictor_wide_intrin_sse2;
+		}
+#    endif
+#    ifdef FLAC__SSSE3_SUPPORTED
+		if (encoder->private_->cpuinfo.ia32.ssse3) {
+			encoder->private_->local_fixed_compute_best_predictor      = FLAC__fixed_compute_best_predictor_intrin_ssse3;
+			encoder->private_->local_fixed_compute_best_predictor_wide = FLAC__fixed_compute_best_predictor_wide_intrin_ssse3;
+		}
+#    endif
+#   endif /* FLAC__HAS_X86INTRIN */
+#  elif defined FLAC__CPU_X86_64
+		FLAC__ASSERT(encoder->private_->cpuinfo.type == FLAC__CPUINFO_TYPE_X86_64);
+#   ifdef FLAC__HAS_X86INTRIN
+#    ifdef FLAC__SSE_SUPPORTED
+		if(encoder->protected_->max_lpc_order < 4)
+			encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_4;
+		else if(encoder->protected_->max_lpc_order < 8)
+			encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_8;
+		else if(encoder->protected_->max_lpc_order < 12)
+			encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_12;
+		else if(encoder->protected_->max_lpc_order < 16)
+			encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_intrin_sse_lag_16;
+#    endif
+
+#    ifdef FLAC__SSE2_SUPPORTED
+		encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit = FLAC__lpc_compute_residual_from_qlp_coefficients_16_intrin_sse2;
+#    endif
+#    ifdef FLAC__SSE4_1_SUPPORTED
+		if(encoder->private_->cpuinfo.x86.sse41) {
+			encoder->private_->local_lpc_compute_residual_from_qlp_coefficients = FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_sse41;
+		}
+#    endif
+#    ifdef FLAC__AVX2_SUPPORTED
+		if(encoder->private_->cpuinfo.x86.avx2) {
+			encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit = FLAC__lpc_compute_residual_from_qlp_coefficients_16_intrin_avx2;
+			encoder->private_->local_lpc_compute_residual_from_qlp_coefficients       = FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_avx2;
+			encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_64bit = FLAC__lpc_compute_residual_from_qlp_coefficients_wide_intrin_avx2;
+		}
+#    endif
+
+#    ifdef FLAC__SSE2_SUPPORTED
+		encoder->private_->local_fixed_compute_best_predictor      = FLAC__fixed_compute_best_predictor_intrin_sse2;
+		encoder->private_->local_fixed_compute_best_predictor_wide = FLAC__fixed_compute_best_predictor_wide_intrin_sse2;
+#    endif
+#    ifdef FLAC__SSSE3_SUPPORTED
+		if (encoder->private_->cpuinfo.x86.ssse3) {
+			encoder->private_->local_fixed_compute_best_predictor      = FLAC__fixed_compute_best_predictor_intrin_ssse3;
+			encoder->private_->local_fixed_compute_best_predictor_wide = FLAC__fixed_compute_best_predictor_wide_intrin_ssse3;
+		}
+#    endif
+#   endif /* FLAC__HAS_X86INTRIN */
+#  endif /* FLAC__CPU_... */
 	}
-#endif
+# endif /* !FLAC__NO_ASM */
+#endif /* !FLAC__INTEGER_ONLY_LIBRARY */
+#if !defined FLAC__NO_ASM && defined FLAC__HAS_X86INTRIN
+	if(encoder->private_->cpuinfo.use_asm) {
+# if defined FLAC__CPU_IA32
+#  ifdef FLAC__SSE2_SUPPORTED
+		if(encoder->private_->cpuinfo.ia32.sse2)
+			encoder->private_->local_precompute_partition_info_sums = FLAC__precompute_partition_info_sums_intrin_sse2;
+#  endif
+#  ifdef FLAC__SSSE3_SUPPORTED
+		if(encoder->private_->cpuinfo.ia32.ssse3)
+			encoder->private_->local_precompute_partition_info_sums = FLAC__precompute_partition_info_sums_intrin_ssse3;
+#  endif
+#  ifdef FLAC__AVX2_SUPPORTED
+		if(encoder->private_->cpuinfo.ia32.avx2)
+			encoder->private_->local_precompute_partition_info_sums = FLAC__precompute_partition_info_sums_intrin_avx2;
+#  endif
+# elif defined FLAC__CPU_X86_64
+#  ifdef FLAC__SSE2_SUPPORTED
+		encoder->private_->local_precompute_partition_info_sums = FLAC__precompute_partition_info_sums_intrin_sse2;
+#  endif
+#  ifdef FLAC__SSSE3_SUPPORTED
+		if(encoder->private_->cpuinfo.x86.ssse3)
+			encoder->private_->local_precompute_partition_info_sums = FLAC__precompute_partition_info_sums_intrin_ssse3;
+#  endif
+#  ifdef FLAC__AVX2_SUPPORTED
+		if(encoder->private_->cpuinfo.x86.avx2)
+			encoder->private_->local_precompute_partition_info_sums = FLAC__precompute_partition_info_sums_intrin_avx2;
+#  endif
+# endif /* FLAC__CPU_... */
+	}
+#endif /* !FLAC__NO_ASM && FLAC__HAS_X86INTRIN */
 	/* 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;
+		encoder->private_->local_fixed_compute_best_predictor = encoder->private_->local_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;
+	/* set state to OK; from here on, errors are fatal and we'll override the state then */
+	encoder->protected_->state = FLAC__STREAM_ENCODER_OK;
 
+#if FLAC__HAS_OGG
+	encoder->private_->is_ogg = is_ogg;
+	if(is_ogg && !FLAC__ogg_encoder_aspect_init(&encoder->protected_->ogg_encoder_aspect)) {
+		encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR;
+		return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
+	}
+#endif
+
+	encoder->private_->read_callback = read_callback;
+	encoder->private_->write_callback = write_callback;
+	encoder->private_->seek_callback = seek_callback;
+	encoder->private_->tell_callback = tell_callback;
+	encoder->private_->metadata_callback = metadata_callback;
+	encoder->private_->client_data = client_data;
+
 	if(!resize_buffers_(encoder, encoder->protected_->blocksize)) {
 		/* the above function sets the state for us in case of an error */
-		return encoder->protected_->state;
+		return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
 	}
 
-	if(!FLAC__bitbuffer_init(encoder->private_->frame))
-		return encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR;
+	if(!FLAC__bitwriter_init(encoder->private_->frame)) {
+		encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR;
+		return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
+	}
 
 	/*
 	 * Set up the verify stuff if necessary
@@ -802,10 +1089,12 @@
 		 * First, set up the fifo which will hold the
 		 * original signal to compare against
 		 */
-		encoder->private_->verify.input_fifo.size = encoder->protected_->blocksize;
+		encoder->private_->verify.input_fifo.size = encoder->protected_->blocksize+OVERREAD_;
 		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;
+			if(0 == (encoder->private_->verify.input_fifo.data[i] = safe_malloc_mul_2op_p(sizeof(FLAC__int32), /*times*/encoder->private_->verify.input_fifo.size))) {
+				encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR;
+				return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
+			}
 		}
 		encoder->private_->verify.input_fifo.tail = 0;
 
@@ -812,17 +1101,18 @@
 		/*
 		 * 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;
+		if(0 == encoder->private_->verify.decoder) {
+			encoder->private_->verify.decoder = FLAC__stream_decoder_new();
+			if(0 == encoder->private_->verify.decoder) {
+				encoder->protected_->state = FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR;
+				return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_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;
+		if(FLAC__stream_decoder_init_stream(encoder->private_->verify.decoder, verify_read_callback_, /*seek_callback=*/0, /*tell_callback=*/0, /*length_callback=*/0, /*eof_callback=*/0, verify_write_callback_, verify_metadata_callback_, verify_error_callback_, /*client_data=*/encoder) != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
+			encoder->protected_->state = FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR;
+			return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
+		}
 	}
 	encoder->private_->verify.error_stats.absolute_sample = 0;
 	encoder->private_->verify.error_stats.frame_number = 0;
@@ -832,15 +1122,27 @@
 	encoder->private_->verify.error_stats.got = 0;
 
 	/*
+	 * These must be done before we write any metadata, 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;
+
+	/*
 	 * 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)) {
+	if(!FLAC__bitwriter_write_raw_uint32(encoder->private_->frame, FLAC__STREAM_SYNC, FLAC__STREAM_SYNC_LEN)) {
+		encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR;
+		return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
+	}
+	if(!write_bitbuffer_(encoder, 0, /*is_last_block=*/false)) {
 		/* the above function sets the state for us in case of an error */
-		return encoder->protected_->state;
+		return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
 	}
 
 	/*
@@ -848,26 +1150,27 @@
 	 */
 	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)) {
+	encoder->private_->streaminfo.type = FLAC__METADATA_TYPE_STREAMINFO;
+	encoder->private_->streaminfo.is_last = false; /* we will have at a minimum a VORBIS_COMMENT afterwards */
+	encoder->private_->streaminfo.length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH;
+	encoder->private_->streaminfo.data.stream_info.min_blocksize = encoder->protected_->blocksize; /* this encoder uses the same blocksize for the whole stream */
+	encoder->private_->streaminfo.data.stream_info.max_blocksize = encoder->protected_->blocksize;
+	encoder->private_->streaminfo.data.stream_info.min_framesize = 0; /* we don't know this yet; have to fill it in later */
+	encoder->private_->streaminfo.data.stream_info.max_framesize = 0; /* we don't know this yet; have to fill it in later */
+	encoder->private_->streaminfo.data.stream_info.sample_rate = encoder->protected_->sample_rate;
+	encoder->private_->streaminfo.data.stream_info.channels = encoder->protected_->channels;
+	encoder->private_->streaminfo.data.stream_info.bits_per_sample = encoder->protected_->bits_per_sample;
+	encoder->private_->streaminfo.data.stream_info.total_samples = encoder->protected_->total_samples_estimate; /* we will replace this later with the real total */
+	memset(encoder->private_->streaminfo.data.stream_info.md5sum, 0, 16); /* we don't know this yet; have to fill it in later */
+	if(encoder->protected_->do_md5)
+		FLAC__MD5Init(&encoder->private_->md5context);
+	if(!FLAC__add_metadata_block(&encoder->private_->streaminfo, encoder->private_->frame)) {
+		encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR;
+		return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
+	}
+	if(!write_bitbuffer_(encoder, 0, /*is_last_block=*/false)) {
 		/* the above function sets the state for us in case of an error */
-		return encoder->protected_->state;
+		return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
 	}
 
 	/*
@@ -874,9 +1177,9 @@
 	 * 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;
+	encoder->private_->streaminfo.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;
+	encoder->private_->streaminfo.data.stream_info.total_samples = 0;
 
 	/*
 	 * Check to see if the supplied metadata contains a VORBIS_COMMENT;
@@ -883,10 +1186,10 @@
 	 * 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.)
+	 * WATCHOUT: the Ogg FLAC mapping requires us to write this block after
+	 * the STREAMINFO.  (In the case that metadata_has_vorbis_comment is
+	 * true it will have already insured that the metadata list is properly
+	 * ordered.)
 	 */
 	if(!metadata_has_vorbis_comment) {
 		FLAC__StreamMetadata vorbis_comment;
@@ -897,13 +1200,13 @@
 		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)) {
+		if(!FLAC__add_metadata_block(&vorbis_comment, encoder->private_->frame)) {
+			encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR;
+			return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
+		}
+		if(!write_bitbuffer_(encoder, 0, /*is_last_block=*/false)) {
 			/* the above function sets the state for us in case of an error */
-			return encoder->protected_->state;
+			return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
 		}
 	}
 
@@ -912,84 +1215,327 @@
 	 */
 	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)) {
+		if(!FLAC__add_metadata_block(encoder->protected_->metadata[i], encoder->private_->frame)) {
+			encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR;
+			return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
+		}
+		if(!write_bitbuffer_(encoder, 0, /*is_last_block=*/false)) {
 			/* the above function sets the state for us in case of an error */
-			return encoder->protected_->state;
+			return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
 		}
 	}
 
+	/* now that all the metadata is written, we save the stream offset */
+	if(encoder->private_->tell_callback && encoder->private_->tell_callback(encoder, &encoder->protected_->audio_offset, encoder->private_->client_data) == FLAC__STREAM_ENCODER_TELL_STATUS_ERROR) { /* FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED just means we didn't get the offset; no error */
+		encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
+		return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
+	}
+
 	if(encoder->protected_->verify)
 		encoder->private_->verify.state_hint = ENCODER_IN_AUDIO;
 
-	return encoder->protected_->state;
+	return FLAC__STREAM_ENCODER_INIT_STATUS_OK;
 }
 
-FLAC_API void FLAC__stream_encoder_finish(FLAC__StreamEncoder *encoder)
+FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_stream(
+	FLAC__StreamEncoder *encoder,
+	FLAC__StreamEncoderWriteCallback write_callback,
+	FLAC__StreamEncoderSeekCallback seek_callback,
+	FLAC__StreamEncoderTellCallback tell_callback,
+	FLAC__StreamEncoderMetadataCallback metadata_callback,
+	void *client_data
+)
 {
+	return init_stream_internal_(
+		encoder,
+		/*read_callback=*/0,
+		write_callback,
+		seek_callback,
+		tell_callback,
+		metadata_callback,
+		client_data,
+		/*is_ogg=*/false
+	);
+}
+
+FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_ogg_stream(
+	FLAC__StreamEncoder *encoder,
+	FLAC__StreamEncoderReadCallback read_callback,
+	FLAC__StreamEncoderWriteCallback write_callback,
+	FLAC__StreamEncoderSeekCallback seek_callback,
+	FLAC__StreamEncoderTellCallback tell_callback,
+	FLAC__StreamEncoderMetadataCallback metadata_callback,
+	void *client_data
+)
+{
+	return init_stream_internal_(
+		encoder,
+		read_callback,
+		write_callback,
+		seek_callback,
+		tell_callback,
+		metadata_callback,
+		client_data,
+		/*is_ogg=*/true
+	);
+}
+
+static FLAC__StreamEncoderInitStatus init_FILE_internal_(
+	FLAC__StreamEncoder *encoder,
+	FILE *file,
+	FLAC__StreamEncoderProgressCallback progress_callback,
+	void *client_data,
+	FLAC__bool is_ogg
+)
+{
+	FLAC__StreamEncoderInitStatus init_status;
+
 	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != file);
 
+	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+		return FLAC__STREAM_ENCODER_INIT_STATUS_ALREADY_INITIALIZED;
+
+	/* double protection */
+	if(file == 0) {
+		encoder->protected_->state = FLAC__STREAM_ENCODER_IO_ERROR;
+		return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
+	}
+
+	/*
+	 * To make sure that our file does not go unclosed after an error, we
+	 * must assign the FILE pointer before any further error can occur in
+	 * this routine.
+	 */
+	if(file == stdout)
+		file = get_binary_stdout_(); /* just to be safe */
+
+#ifdef _WIN32
+	/*
+	 * Windows can suffer quite badly from disk fragmentation. This can be
+	 * reduced significantly by setting the output buffer size to be 10MB.
+	 */
+	setvbuf(file, NULL, _IOFBF, 10*1024*1024);
+#endif
+	encoder->private_->file = file;
+
+	encoder->private_->progress_callback = progress_callback;
+	encoder->private_->bytes_written = 0;
+	encoder->private_->samples_written = 0;
+	encoder->private_->frames_written = 0;
+
+	init_status = init_stream_internal_(
+		encoder,
+		encoder->private_->file == stdout? 0 : is_ogg? file_read_callback_ : 0,
+		file_write_callback_,
+		encoder->private_->file == stdout? 0 : file_seek_callback_,
+		encoder->private_->file == stdout? 0 : file_tell_callback_,
+		/*metadata_callback=*/0,
+		client_data,
+		is_ogg
+	);
+	if(init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) {
+		/* the above function sets the state for us in case of an error */
+		return init_status;
+	}
+
+	{
+		unsigned blocksize = FLAC__stream_encoder_get_blocksize(encoder);
+
+		FLAC__ASSERT(blocksize != 0);
+		encoder->private_->total_frames_estimate = (unsigned)((FLAC__stream_encoder_get_total_samples_estimate(encoder) + blocksize - 1) / blocksize);
+	}
+
+	return init_status;
+}
+
+FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_FILE(
+	FLAC__StreamEncoder *encoder,
+	FILE *file,
+	FLAC__StreamEncoderProgressCallback progress_callback,
+	void *client_data
+)
+{
+	return init_FILE_internal_(encoder, file, progress_callback, client_data, /*is_ogg=*/false);
+}
+
+FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_ogg_FILE(
+	FLAC__StreamEncoder *encoder,
+	FILE *file,
+	FLAC__StreamEncoderProgressCallback progress_callback,
+	void *client_data
+)
+{
+	return init_FILE_internal_(encoder, file, progress_callback, client_data, /*is_ogg=*/true);
+}
+
+static FLAC__StreamEncoderInitStatus init_file_internal_(
+	FLAC__StreamEncoder *encoder,
+	const char *filename,
+	FLAC__StreamEncoderProgressCallback progress_callback,
+	void *client_data,
+	FLAC__bool is_ogg
+)
+{
+	FILE *file;
+
+	FLAC__ASSERT(0 != encoder);
+
+	/*
+	 * To make sure that our file does not go unclosed after an error, we
+	 * have to do the same entrance checks here that are later performed
+	 * in FLAC__stream_encoder_init_FILE() before the FILE* is assigned.
+	 */
+	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+		return FLAC__STREAM_ENCODER_INIT_STATUS_ALREADY_INITIALIZED;
+
+	file = filename? flac_fopen(filename, "w+b") : stdout;
+
+	if(file == 0) {
+		encoder->protected_->state = FLAC__STREAM_ENCODER_IO_ERROR;
+		return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
+	}
+
+	return init_FILE_internal_(encoder, file, progress_callback, client_data, is_ogg);
+}
+
+FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_file(
+	FLAC__StreamEncoder *encoder,
+	const char *filename,
+	FLAC__StreamEncoderProgressCallback progress_callback,
+	void *client_data
+)
+{
+	return init_file_internal_(encoder, filename, progress_callback, client_data, /*is_ogg=*/false);
+}
+
+FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_ogg_file(
+	FLAC__StreamEncoder *encoder,
+	const char *filename,
+	FLAC__StreamEncoderProgressCallback progress_callback,
+	void *client_data
+)
+{
+	return init_file_internal_(encoder, filename, progress_callback, client_data, /*is_ogg=*/true);
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_finish(FLAC__StreamEncoder *encoder)
+{
+	FLAC__bool error = false;
+
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+
 	if(encoder->protected_->state == FLAC__STREAM_ENCODER_UNINITIALIZED)
-		return;
+		return true;
 
 	if(encoder->protected_->state == FLAC__STREAM_ENCODER_OK && !encoder->private_->is_being_deleted) {
 		if(encoder->private_->current_sample_number != 0) {
+			const FLAC__bool is_fractional_block = encoder->protected_->blocksize != encoder->private_->current_sample_number;
 			encoder->protected_->blocksize = encoder->private_->current_sample_number;
-			process_frame_(encoder, true); /* true => is last frame */
+			if(!process_frame_(encoder, is_fractional_block, /*is_last_block=*/true))
+				error = true;
 		}
 	}
 
-	FLAC__MD5Final(encoder->private_->metadata.data.stream_info.md5sum, &encoder->private_->md5context);
+	if(encoder->protected_->do_md5)
+		FLAC__MD5Final(encoder->private_->streaminfo.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->private_->is_being_deleted) {
+		if(encoder->protected_->state == FLAC__STREAM_ENCODER_OK) {
+			if(encoder->private_->seek_callback) {
+#if FLAC__HAS_OGG
+				if(encoder->private_->is_ogg)
+					update_ogg_metadata_(encoder);
+				else
+#endif
+				update_metadata_(encoder);
+
+				/* check if an error occurred while updating metadata */
+				if(encoder->protected_->state != FLAC__STREAM_ENCODER_OK)
+					error = true;
+			}
+			if(encoder->private_->metadata_callback)
+				encoder->private_->metadata_callback(encoder, &encoder->private_->streaminfo, encoder->private_->client_data);
+		}
+
+		if(encoder->protected_->verify && 0 != encoder->private_->verify.decoder && !FLAC__stream_decoder_finish(encoder->private_->verify.decoder)) {
+			if(!error)
+				encoder->protected_->state = FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA;
+			error = true;
+		}
 	}
 
-	if(encoder->protected_->verify && 0 != encoder->private_->verify.decoder)
-		FLAC__stream_decoder_finish(encoder->private_->verify.decoder);
+	if(0 != encoder->private_->file) {
+		if(encoder->private_->file != stdout)
+			fclose(encoder->private_->file);
+		encoder->private_->file = 0;
+	}
 
+#if FLAC__HAS_OGG
+	if(encoder->private_->is_ogg)
+		FLAC__ogg_encoder_aspect_finish(&encoder->protected_->ogg_encoder_aspect);
+#endif
+
 	free_(encoder);
 	set_defaults_(encoder);
 
-	encoder->protected_->state = FLAC__STREAM_ENCODER_UNINITIALIZED;
+	if(!error)
+		encoder->protected_->state = FLAC__STREAM_ENCODER_UNINITIALIZED;
+
+	return !error;
 }
 
-FLAC_API FLAC__bool FLAC__stream_encoder_set_verify(FLAC__StreamEncoder *encoder, FLAC__bool value)
+FLAC_API FLAC__bool FLAC__stream_encoder_set_ogg_serial_number(FLAC__StreamEncoder *encoder, long value)
 {
 	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
 	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
 		return false;
-	encoder->protected_->verify = value;
+#if FLAC__HAS_OGG
+	/* can't check encoder->private_->is_ogg since that's not set until init time */
+	FLAC__ogg_encoder_aspect_set_serial_number(&encoder->protected_->ogg_encoder_aspect, value);
 	return true;
+#else
+	(void)value;
+	return false;
+#endif
 }
 
-FLAC_API FLAC__bool FLAC__stream_encoder_set_streamable_subset(FLAC__StreamEncoder *encoder, FLAC__bool value)
+FLAC_API FLAC__bool FLAC__stream_encoder_set_verify(FLAC__StreamEncoder *encoder, FLAC__bool value)
 {
 	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
 	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
 		return false;
-	encoder->protected_->streamable_subset = value;
+#ifndef FLAC__MANDATORY_VERIFY_WHILE_ENCODING
+	encoder->protected_->verify = value;
+#endif
 	return true;
 }
 
-FLAC_API FLAC__bool FLAC__stream_encoder_set_do_mid_side_stereo(FLAC__StreamEncoder *encoder, FLAC__bool value)
+FLAC_API FLAC__bool FLAC__stream_encoder_set_streamable_subset(FLAC__StreamEncoder *encoder, FLAC__bool value)
 {
 	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
 	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
 		return false;
-	encoder->protected_->do_mid_side_stereo = value;
+	encoder->protected_->streamable_subset = value;
 	return true;
 }
 
-FLAC_API FLAC__bool FLAC__stream_encoder_set_loose_mid_side_stereo(FLAC__StreamEncoder *encoder, FLAC__bool value)
+FLAC_API FLAC__bool FLAC__stream_encoder_set_do_md5(FLAC__StreamEncoder *encoder, FLAC__bool value)
 {
 	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
 	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
 		return false;
-	encoder->protected_->loose_mid_side_stereo = value;
+	encoder->protected_->do_md5 = value;
 	return true;
 }
 
@@ -996,6 +1542,8 @@
 FLAC_API FLAC__bool FLAC__stream_encoder_set_channels(FLAC__StreamEncoder *encoder, unsigned value)
 {
 	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
 	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
 		return false;
 	encoder->protected_->channels = value;
@@ -1005,6 +1553,8 @@
 FLAC_API FLAC__bool FLAC__stream_encoder_set_bits_per_sample(FLAC__StreamEncoder *encoder, unsigned value)
 {
 	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
 	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
 		return false;
 	encoder->protected_->bits_per_sample = value;
@@ -1014,6 +1564,8 @@
 FLAC_API FLAC__bool FLAC__stream_encoder_set_sample_rate(FLAC__StreamEncoder *encoder, unsigned value)
 {
 	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
 	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
 		return false;
 	encoder->protected_->sample_rate = value;
@@ -1020,9 +1572,44 @@
 	return true;
 }
 
+FLAC_API FLAC__bool FLAC__stream_encoder_set_compression_level(FLAC__StreamEncoder *encoder, unsigned value)
+{
+	FLAC__bool ok = true;
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+		return false;
+	if(value >= sizeof(compression_levels_)/sizeof(compression_levels_[0]))
+		value = sizeof(compression_levels_)/sizeof(compression_levels_[0]) - 1;
+	ok &= FLAC__stream_encoder_set_do_mid_side_stereo          (encoder, compression_levels_[value].do_mid_side_stereo);
+	ok &= FLAC__stream_encoder_set_loose_mid_side_stereo       (encoder, compression_levels_[value].loose_mid_side_stereo);
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+#if 1
+	ok &= FLAC__stream_encoder_set_apodization                 (encoder, compression_levels_[value].apodization);
+#else
+	/* equivalent to -A tukey(0.5) */
+	encoder->protected_->num_apodizations = 1;
+	encoder->protected_->apodizations[0].type = FLAC__APODIZATION_TUKEY;
+	encoder->protected_->apodizations[0].parameters.tukey.p = 0.5;
+#endif
+#endif
+	ok &= FLAC__stream_encoder_set_max_lpc_order               (encoder, compression_levels_[value].max_lpc_order);
+	ok &= FLAC__stream_encoder_set_qlp_coeff_precision         (encoder, compression_levels_[value].qlp_coeff_precision);
+	ok &= FLAC__stream_encoder_set_do_qlp_coeff_prec_search    (encoder, compression_levels_[value].do_qlp_coeff_prec_search);
+	ok &= FLAC__stream_encoder_set_do_escape_coding            (encoder, compression_levels_[value].do_escape_coding);
+	ok &= FLAC__stream_encoder_set_do_exhaustive_model_search  (encoder, compression_levels_[value].do_exhaustive_model_search);
+	ok &= FLAC__stream_encoder_set_min_residual_partition_order(encoder, compression_levels_[value].min_residual_partition_order);
+	ok &= FLAC__stream_encoder_set_max_residual_partition_order(encoder, compression_levels_[value].max_residual_partition_order);
+	ok &= FLAC__stream_encoder_set_rice_parameter_search_dist  (encoder, compression_levels_[value].rice_parameter_search_dist);
+	return ok;
+}
+
 FLAC_API FLAC__bool FLAC__stream_encoder_set_blocksize(FLAC__StreamEncoder *encoder, unsigned value)
 {
 	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
 	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
 		return false;
 	encoder->protected_->blocksize = value;
@@ -1029,9 +1616,147 @@
 	return true;
 }
 
+FLAC_API FLAC__bool FLAC__stream_encoder_set_do_mid_side_stereo(FLAC__StreamEncoder *encoder, FLAC__bool value)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	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);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+		return false;
+	encoder->protected_->loose_mid_side_stereo = value;
+	return true;
+}
+
+/*@@@@add to tests*/
+FLAC_API FLAC__bool FLAC__stream_encoder_set_apodization(FLAC__StreamEncoder *encoder, const char *specification)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	FLAC__ASSERT(0 != specification);
+	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+		return false;
+#ifdef FLAC__INTEGER_ONLY_LIBRARY
+	(void)specification; /* silently ignore since we haven't integerized; will always use a rectangular window */
+#else
+	encoder->protected_->num_apodizations = 0;
+	while(1) {
+		const char *s = strchr(specification, ';');
+		const size_t n = s? (size_t)(s - specification) : strlen(specification);
+		if     (n==8  && 0 == strncmp("bartlett"     , specification, n))
+			encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_BARTLETT;
+		else if(n==13 && 0 == strncmp("bartlett_hann", specification, n))
+			encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_BARTLETT_HANN;
+		else if(n==8  && 0 == strncmp("blackman"     , specification, n))
+			encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_BLACKMAN;
+		else if(n==26 && 0 == strncmp("blackman_harris_4term_92db", specification, n))
+			encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_BLACKMAN_HARRIS_4TERM_92DB_SIDELOBE;
+		else if(n==6  && 0 == strncmp("connes"       , specification, n))
+			encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_CONNES;
+		else if(n==7  && 0 == strncmp("flattop"      , specification, n))
+			encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_FLATTOP;
+		else if(n>7   && 0 == strncmp("gauss("       , specification, 6)) {
+			FLAC__real stddev = (FLAC__real)strtod(specification+6, 0);
+			if (stddev > 0.0 && stddev <= 0.5) {
+				encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.gauss.stddev = stddev;
+				encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_GAUSS;
+			}
+		}
+		else if(n==7  && 0 == strncmp("hamming"      , specification, n))
+			encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_HAMMING;
+		else if(n==4  && 0 == strncmp("hann"         , specification, n))
+			encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_HANN;
+		else if(n==13 && 0 == strncmp("kaiser_bessel", specification, n))
+			encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_KAISER_BESSEL;
+		else if(n==7  && 0 == strncmp("nuttall"      , specification, n))
+			encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_NUTTALL;
+		else if(n==9  && 0 == strncmp("rectangle"    , specification, n))
+			encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_RECTANGLE;
+		else if(n==8  && 0 == strncmp("triangle"     , specification, n))
+			encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_TRIANGLE;
+		else if(n>7   && 0 == strncmp("tukey("       , specification, 6)) {
+			FLAC__real p = (FLAC__real)strtod(specification+6, 0);
+			if (p >= 0.0 && p <= 1.0) {
+				encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.tukey.p = p;
+				encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_TUKEY;
+			}
+		}
+		else if(n>15   && 0 == strncmp("partial_tukey("       , specification, 14)) {
+			FLAC__int32 tukey_parts = (FLAC__int32)strtod(specification+14, 0);
+			const char *si_1 = strchr(specification, '/');
+			FLAC__real overlap = si_1?flac_min((FLAC__real)strtod(si_1+1, 0),0.99f):0.1f;
+			FLAC__real overlap_units = 1.0f/(1.0f - overlap) - 1.0f;
+			const char *si_2 = strchr((si_1?(si_1+1):specification), '/');
+			FLAC__real tukey_p = si_2?(FLAC__real)strtod(si_2+1, 0):0.2f;
+
+			if (tukey_parts <= 1) {
+				encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.tukey.p = tukey_p;
+				encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_TUKEY;
+			}else if (encoder->protected_->num_apodizations + tukey_parts < 32){
+				FLAC__int32 m;
+				for(m = 0; m < tukey_parts; m++){
+					encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.multiple_tukey.p = tukey_p;
+					encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.multiple_tukey.start = m/(tukey_parts+overlap_units);
+					encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.multiple_tukey.end = (m+1+overlap_units)/(tukey_parts+overlap_units);
+					encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_PARTIAL_TUKEY;
+				}
+			}
+		}
+		else if(n>16   && 0 == strncmp("punchout_tukey("       , specification, 15)) {
+			FLAC__int32 tukey_parts = (FLAC__int32)strtod(specification+15, 0);
+			const char *si_1 = strchr(specification, '/');
+			FLAC__real overlap = si_1?flac_min((FLAC__real)strtod(si_1+1, 0),0.99f):0.2f;
+			FLAC__real overlap_units = 1.0f/(1.0f - overlap) - 1.0f;
+			const char *si_2 = strchr((si_1?(si_1+1):specification), '/');
+			FLAC__real tukey_p = si_2?(FLAC__real)strtod(si_2+1, 0):0.2f;
+
+			if (tukey_parts <= 1) {
+				encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.tukey.p = tukey_p;
+				encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_TUKEY;
+			}else if (encoder->protected_->num_apodizations + tukey_parts < 32){
+				FLAC__int32 m;
+				for(m = 0; m < tukey_parts; m++){
+					encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.multiple_tukey.p = tukey_p;
+					encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.multiple_tukey.start = m/(tukey_parts+overlap_units);
+					encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.multiple_tukey.end = (m+1+overlap_units)/(tukey_parts+overlap_units);
+					encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_PUNCHOUT_TUKEY;
+				}
+			}
+		}
+		else if(n==5  && 0 == strncmp("welch"        , specification, n))
+			encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_WELCH;
+		if (encoder->protected_->num_apodizations == 32)
+			break;
+		if (s)
+			specification = s+1;
+		else
+			break;
+	}
+	if(encoder->protected_->num_apodizations == 0) {
+		encoder->protected_->num_apodizations = 1;
+		encoder->protected_->apodizations[0].type = FLAC__APODIZATION_TUKEY;
+		encoder->protected_->apodizations[0].parameters.tukey.p = 0.5;
+	}
+#endif
+	return true;
+}
+
 FLAC_API FLAC__bool FLAC__stream_encoder_set_max_lpc_order(FLAC__StreamEncoder *encoder, unsigned value)
 {
 	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
 	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
 		return false;
 	encoder->protected_->max_lpc_order = value;
@@ -1041,6 +1766,8 @@
 FLAC_API FLAC__bool FLAC__stream_encoder_set_qlp_coeff_precision(FLAC__StreamEncoder *encoder, unsigned value)
 {
 	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
 	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
 		return false;
 	encoder->protected_->qlp_coeff_precision = value;
@@ -1050,6 +1777,8 @@
 FLAC_API FLAC__bool FLAC__stream_encoder_set_do_qlp_coeff_prec_search(FLAC__StreamEncoder *encoder, FLAC__bool value)
 {
 	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
 	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
 		return false;
 	encoder->protected_->do_qlp_coeff_prec_search = value;
@@ -1059,6 +1788,8 @@
 FLAC_API FLAC__bool FLAC__stream_encoder_set_do_escape_coding(FLAC__StreamEncoder *encoder, FLAC__bool value)
 {
 	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
 	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
 		return false;
 #if 0
@@ -1073,6 +1804,8 @@
 FLAC_API FLAC__bool FLAC__stream_encoder_set_do_exhaustive_model_search(FLAC__StreamEncoder *encoder, FLAC__bool value)
 {
 	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
 	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
 		return false;
 	encoder->protected_->do_exhaustive_model_search = value;
@@ -1082,6 +1815,8 @@
 FLAC_API FLAC__bool FLAC__stream_encoder_set_min_residual_partition_order(FLAC__StreamEncoder *encoder, unsigned value)
 {
 	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
 	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
 		return false;
 	encoder->protected_->min_residual_partition_order = value;
@@ -1091,6 +1826,8 @@
 FLAC_API FLAC__bool FLAC__stream_encoder_set_max_residual_partition_order(FLAC__StreamEncoder *encoder, unsigned value)
 {
 	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
 	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
 		return false;
 	encoder->protected_->max_residual_partition_order = value;
@@ -1100,6 +1837,8 @@
 FLAC_API FLAC__bool FLAC__stream_encoder_set_rice_parameter_search_dist(FLAC__StreamEncoder *encoder, unsigned value)
 {
 	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
 	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
 		return false;
 #if 0
@@ -1114,6 +1853,8 @@
 FLAC_API FLAC__bool FLAC__stream_encoder_set_total_samples_estimate(FLAC__StreamEncoder *encoder, FLAC__uint64 value)
 {
 	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
 	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
 		return false;
 	encoder->protected_->total_samples_estimate = value;
@@ -1123,42 +1864,35 @@
 FLAC_API FLAC__bool FLAC__stream_encoder_set_metadata(FLAC__StreamEncoder *encoder, FLAC__StreamMetadata **metadata, unsigned num_blocks)
 {
 	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
 	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)
+	if(0 == metadata)
+		num_blocks = 0;
+	if(0 == num_blocks)
+		metadata = 0;
+	/* realloc() does not do exactly what we want so... */
+	if(encoder->protected_->metadata) {
+		free(encoder->protected_->metadata);
+		encoder->protected_->metadata = 0;
+		encoder->protected_->num_metadata_blocks = 0;
+	}
+	if(num_blocks) {
+		FLAC__StreamMetadata **m;
+		if(0 == (m = safe_malloc_mul_2op_p(sizeof(m[0]), /*times*/num_blocks)))
+			return false;
+		memcpy(m, metadata, sizeof(m[0]) * num_blocks);
+		encoder->protected_->metadata = m;
+		encoder->protected_->num_metadata_blocks = num_blocks;
+	}
+#if FLAC__HAS_OGG
+	if(!FLAC__ogg_encoder_aspect_set_num_metadata(&encoder->protected_->ogg_encoder_aspect, num_blocks))
 		return false;
-	encoder->private_->write_callback = value;
+#endif
 	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.
@@ -1166,6 +1900,8 @@
 FLAC_API FLAC__bool FLAC__stream_encoder_disable_constant_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value)
 {
 	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
 	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
 		return false;
 	encoder->private_->disable_constant_subframes = value;
@@ -1175,6 +1911,8 @@
 FLAC_API FLAC__bool FLAC__stream_encoder_disable_fixed_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value)
 {
 	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
 	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
 		return false;
 	encoder->private_->disable_fixed_subframes = value;
@@ -1184,6 +1922,8 @@
 FLAC_API FLAC__bool FLAC__stream_encoder_disable_verbatim_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value)
 {
 	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
 	if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
 		return false;
 	encoder->private_->disable_verbatim_subframes = value;
@@ -1193,6 +1933,8 @@
 FLAC_API FLAC__StreamEncoderState FLAC__stream_encoder_get_state(const FLAC__StreamEncoder *encoder)
 {
 	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
 	return encoder->protected_->state;
 }
 
@@ -1199,6 +1941,8 @@
 FLAC_API FLAC__StreamDecoderState FLAC__stream_encoder_get_verify_decoder_state(const FLAC__StreamEncoder *encoder)
 {
 	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
 	if(encoder->protected_->verify)
 		return FLAC__stream_decoder_get_state(encoder->private_->verify.decoder);
 	else
@@ -1207,6 +1951,9 @@
 
 FLAC_API const char *FLAC__stream_encoder_get_resolved_state_string(const FLAC__StreamEncoder *encoder)
 {
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
 	if(encoder->protected_->state != FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR)
 		return FLAC__StreamEncoderStateString[encoder->protected_->state];
 	else
@@ -1216,6 +1963,8 @@
 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);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
 	if(0 != absolute_sample)
 		*absolute_sample = encoder->private_->verify.error_stats.absolute_sample;
 	if(0 != frame_number)
@@ -1233,6 +1982,8 @@
 FLAC_API FLAC__bool FLAC__stream_encoder_get_verify(const FLAC__StreamEncoder *encoder)
 {
 	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
 	return encoder->protected_->verify;
 }
 
@@ -1239,24 +1990,24 @@
 FLAC_API FLAC__bool FLAC__stream_encoder_get_streamable_subset(const FLAC__StreamEncoder *encoder)
 {
 	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
 	return encoder->protected_->streamable_subset;
 }
 
-FLAC_API FLAC__bool FLAC__stream_encoder_get_do_mid_side_stereo(const FLAC__StreamEncoder *encoder)
+FLAC_API FLAC__bool FLAC__stream_encoder_get_do_md5(const FLAC__StreamEncoder *encoder)
 {
 	FLAC__ASSERT(0 != encoder);
-	return encoder->protected_->do_mid_side_stereo;
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	return encoder->protected_->do_md5;
 }
 
-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);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
 	return encoder->protected_->channels;
 }
 
@@ -1263,6 +2014,8 @@
 FLAC_API unsigned FLAC__stream_encoder_get_bits_per_sample(const FLAC__StreamEncoder *encoder)
 {
 	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
 	return encoder->protected_->bits_per_sample;
 }
 
@@ -1269,6 +2022,8 @@
 FLAC_API unsigned FLAC__stream_encoder_get_sample_rate(const FLAC__StreamEncoder *encoder)
 {
 	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
 	return encoder->protected_->sample_rate;
 }
 
@@ -1275,12 +2030,32 @@
 FLAC_API unsigned FLAC__stream_encoder_get_blocksize(const FLAC__StreamEncoder *encoder)
 {
 	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
 	return encoder->protected_->blocksize;
 }
 
+FLAC_API FLAC__bool FLAC__stream_encoder_get_do_mid_side_stereo(const FLAC__StreamEncoder *encoder)
+{
+	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	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);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
+	return encoder->protected_->loose_mid_side_stereo;
+}
+
 FLAC_API unsigned FLAC__stream_encoder_get_max_lpc_order(const FLAC__StreamEncoder *encoder)
 {
 	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
 	return encoder->protected_->max_lpc_order;
 }
 
@@ -1287,6 +2062,8 @@
 FLAC_API unsigned FLAC__stream_encoder_get_qlp_coeff_precision(const FLAC__StreamEncoder *encoder)
 {
 	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
 	return encoder->protected_->qlp_coeff_precision;
 }
 
@@ -1293,6 +2070,8 @@
 FLAC_API FLAC__bool FLAC__stream_encoder_get_do_qlp_coeff_prec_search(const FLAC__StreamEncoder *encoder)
 {
 	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
 	return encoder->protected_->do_qlp_coeff_prec_search;
 }
 
@@ -1299,6 +2078,8 @@
 FLAC_API FLAC__bool FLAC__stream_encoder_get_do_escape_coding(const FLAC__StreamEncoder *encoder)
 {
 	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
 	return encoder->protected_->do_escape_coding;
 }
 
@@ -1305,6 +2086,8 @@
 FLAC_API FLAC__bool FLAC__stream_encoder_get_do_exhaustive_model_search(const FLAC__StreamEncoder *encoder)
 {
 	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
 	return encoder->protected_->do_exhaustive_model_search;
 }
 
@@ -1311,6 +2094,8 @@
 FLAC_API unsigned FLAC__stream_encoder_get_min_residual_partition_order(const FLAC__StreamEncoder *encoder)
 {
 	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
 	return encoder->protected_->min_residual_partition_order;
 }
 
@@ -1317,6 +2102,8 @@
 FLAC_API unsigned FLAC__stream_encoder_get_max_residual_partition_order(const FLAC__StreamEncoder *encoder)
 {
 	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
 	return encoder->protected_->max_residual_partition_order;
 }
 
@@ -1323,6 +2110,8 @@
 FLAC_API unsigned FLAC__stream_encoder_get_rice_parameter_search_dist(const FLAC__StreamEncoder *encoder)
 {
 	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
 	return encoder->protected_->rice_parameter_search_dist;
 }
 
@@ -1329,65 +2118,59 @@
 FLAC_API FLAC__uint64 FLAC__stream_encoder_get_total_samples_estimate(const FLAC__StreamEncoder *encoder)
 {
 	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
 	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;
+	unsigned i, j = 0, channel;
 	const unsigned channels = encoder->protected_->channels, blocksize = encoder->protected_->blocksize;
 
 	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
 	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));
+	do {
+		const unsigned n = flac_min(blocksize+OVERREAD_-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(encoder->protected_->verify)
+			append_to_verify_fifo_(&encoder->private_->verify.input_fifo, buffer, j, channels, n);
+
+		for(channel = 0; channel < channels; channel++)
+			memcpy(&encoder->private_->integer_signal[channel][encoder->private_->current_sample_number], &buffer[channel][j], sizeof(buffer[channel][0]) * n);
+
+		if(encoder->protected_->do_mid_side_stereo) {
+			FLAC__ASSERT(channels == 2);
+			/* "i <= blocksize" to overread 1 sample; see comment in OVERREAD_ decl */
+			for(i = encoder->private_->current_sample_number; i <= blocksize && j < samples; i++, j++) {
+				encoder->private_->integer_signal_mid_side[1][i] = buffer[0][j] - buffer[1][j];
+				encoder->private_->integer_signal_mid_side[0][i] = (buffer[0][j] + buffer[1][j]) >> 1; /* NOTE: not the same as 'mid = (buffer[0][j] + buffer[1][j]) / 2' ! */
 			}
-			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));
+		}
+		else
+			j += n;
 
-			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++;
+		encoder->private_->current_sample_number += n;
+
+		/* we only process if we have a full block + 1 extra sample; final block is always handled by FLAC__stream_encoder_finish() */
+		if(encoder->private_->current_sample_number > blocksize) {
+			FLAC__ASSERT(encoder->private_->current_sample_number == blocksize+OVERREAD_);
+			FLAC__ASSERT(OVERREAD_ == 1); /* assert we only overread 1 sample which simplifies the rest of the code below */
+			if(!process_frame_(encoder, /*is_fractional_block=*/false, /*is_last_block=*/false))
+				return false;
+			/* move unprocessed overread samples to beginnings of arrays */
+			for(channel = 0; channel < channels; channel++)
+				encoder->private_->integer_signal[channel][0] = encoder->private_->integer_signal[channel][blocksize];
+			if(encoder->protected_->do_mid_side_stereo) {
+				encoder->private_->integer_signal_mid_side[0][0] = encoder->private_->integer_signal_mid_side[0][blocksize];
+				encoder->private_->integer_signal_mid_side[1][0] = encoder->private_->integer_signal_mid_side[1][blocksize];
 			}
-			if(i == blocksize) {
-				if(!process_frame_(encoder, false)) /* false => not last frame */
-					return false;
-			}
-		} while(j < samples);
-	}
+			encoder->private_->current_sample_number = 1;
+		}
+	} while(j < samples);
 
 	return true;
 }
@@ -1399,52 +2182,74 @@
 	const unsigned channels = encoder->protected_->channels, blocksize = encoder->protected_->blocksize;
 
 	FLAC__ASSERT(0 != encoder);
+	FLAC__ASSERT(0 != encoder->private_);
+	FLAC__ASSERT(0 != encoder->protected_);
 	FLAC__ASSERT(encoder->protected_->state == FLAC__STREAM_ENCODER_OK);
 
 	j = k = 0;
+	/*
+	 * we have several flavors of the same basic loop, optimized for
+	 * different conditions:
+	 */
 	if(encoder->protected_->do_mid_side_stereo && channels == 2) {
+		/*
+		 * stereo coding: unroll channel loop
+		 */
 		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));
+				append_to_verify_fifo_interleaved_(&encoder->private_->verify.input_fifo, buffer, j, channels, flac_min(blocksize+OVERREAD_-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;
+			/* "i <= blocksize" to overread 1 sample; see comment in OVERREAD_ decl */
+			for(i = encoder->private_->current_sample_number; i <= blocksize && j < samples; i++, j++) {
+				encoder->private_->integer_signal[0][i] = mid = side = buffer[k++];
 				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 */
+			encoder->private_->current_sample_number = i;
+			/* we only process if we have a full block + 1 extra sample; final block is always handled by FLAC__stream_encoder_finish() */
+			if(i > blocksize) {
+				if(!process_frame_(encoder, /*is_fractional_block=*/false, /*is_last_block=*/false))
 					return false;
+				/* move unprocessed overread samples to beginnings of arrays */
+				FLAC__ASSERT(i == blocksize+OVERREAD_);
+				FLAC__ASSERT(OVERREAD_ == 1); /* assert we only overread 1 sample which simplifies the rest of the code below */
+				encoder->private_->integer_signal[0][0] = encoder->private_->integer_signal[0][blocksize];
+				encoder->private_->integer_signal[1][0] = encoder->private_->integer_signal[1][blocksize];
+				encoder->private_->integer_signal_mid_side[0][0] = encoder->private_->integer_signal_mid_side[0][blocksize];
+				encoder->private_->integer_signal_mid_side[1][0] = encoder->private_->integer_signal_mid_side[1][blocksize];
+				encoder->private_->current_sample_number = 1;
 			}
 		} while(j < samples);
 	}
 	else {
+		/*
+		 * independent channel coding: buffer each channel in inner loop
+		 */
 		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));
+				append_to_verify_fifo_interleaved_(&encoder->private_->verify.input_fifo, buffer, j, channels, flac_min(blocksize+OVERREAD_-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++;
+			/* "i <= blocksize" to overread 1 sample; see comment in OVERREAD_ decl */
+			for(i = encoder->private_->current_sample_number; i <= blocksize && j < samples; i++, j++) {
+				for(channel = 0; channel < channels; channel++)
+					encoder->private_->integer_signal[channel][i] = buffer[k++];
 			}
-			if(i == blocksize) {
-				if(!process_frame_(encoder, false)) /* false => not last frame */
+			encoder->private_->current_sample_number = i;
+			/* we only process if we have a full block + 1 extra sample; final block is always handled by FLAC__stream_encoder_finish() */
+			if(i > blocksize) {
+				if(!process_frame_(encoder, /*is_fractional_block=*/false, /*is_last_block=*/false))
 					return false;
+				/* move unprocessed overread samples to beginnings of arrays */
+				FLAC__ASSERT(i == blocksize+OVERREAD_);
+				FLAC__ASSERT(OVERREAD_ == 1); /* assert we only overread 1 sample which simplifies the rest of the code below */
+				for(channel = 0; channel < channels; channel++)
+					encoder->private_->integer_signal[channel][0] = encoder->private_->integer_signal[channel][blocksize];
+				encoder->private_->current_sample_number = 1;
 			}
 		} while(j < samples);
 	}
@@ -1462,14 +2267,24 @@
 {
 	FLAC__ASSERT(0 != encoder);
 
+#ifdef FLAC__MANDATORY_VERIFY_WHILE_ENCODING
+	encoder->protected_->verify = true;
+#else
 	encoder->protected_->verify = false;
+#endif
 	encoder->protected_->streamable_subset = true;
+	encoder->protected_->do_md5 = 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_->blocksize = 0;
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+	encoder->protected_->num_apodizations = 1;
+	encoder->protected_->apodizations[0].type = FLAC__APODIZATION_TUKEY;
+	encoder->protected_->apodizations[0].parameters.tukey.p = 0.5;
+#endif
 	encoder->protected_->max_lpc_order = 0;
 	encoder->protected_->qlp_coeff_precision = 0;
 	encoder->protected_->do_qlp_coeff_prec_search = false;
@@ -1482,12 +2297,26 @@
 	encoder->protected_->metadata = 0;
 	encoder->protected_->num_metadata_blocks = 0;
 
+	encoder->private_->seek_table = 0;
 	encoder->private_->disable_constant_subframes = false;
 	encoder->private_->disable_fixed_subframes = false;
 	encoder->private_->disable_verbatim_subframes = false;
+#if FLAC__HAS_OGG
+	encoder->private_->is_ogg = false;
+#endif
+	encoder->private_->read_callback = 0;
 	encoder->private_->write_callback = 0;
+	encoder->private_->seek_callback = 0;
+	encoder->private_->tell_callback = 0;
 	encoder->private_->metadata_callback = 0;
+	encoder->private_->progress_callback = 0;
 	encoder->private_->client_data = 0;
+
+#if FLAC__HAS_OGG
+	FLAC__ogg_encoder_aspect_set_defaults(&encoder->protected_->ogg_encoder_aspect);
+#endif
+
+	FLAC__stream_encoder_set_compression_level(encoder, 5);
 }
 
 void free_(FLAC__StreamEncoder *encoder)
@@ -1495,15 +2324,22 @@
 	unsigned i, channel;
 
 	FLAC__ASSERT(0 != encoder);
+	if(encoder->protected_->metadata) {
+		free(encoder->protected_->metadata);
+		encoder->protected_->metadata = 0;
+		encoder->protected_->num_metadata_blocks = 0;
+	}
 	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;
 		}
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
 		if(0 != encoder->private_->real_signal_unaligned[i]) {
 			free(encoder->private_->real_signal_unaligned[i]);
 			encoder->private_->real_signal_unaligned[i] = 0;
 		}
+#endif
 	}
 	for(i = 0; i < 2; i++) {
 		if(0 != encoder->private_->integer_signal_mid_side_unaligned[i]) {
@@ -1510,11 +2346,25 @@
 			free(encoder->private_->integer_signal_mid_side_unaligned[i]);
 			encoder->private_->integer_signal_mid_side_unaligned[i] = 0;
 		}
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
 		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;
 		}
+#endif
 	}
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+	for(i = 0; i < encoder->protected_->num_apodizations; i++) {
+		if(0 != encoder->private_->window_unaligned[i]) {
+			free(encoder->private_->window_unaligned[i]);
+			encoder->private_->window_unaligned[i] = 0;
+		}
+	}
+	if(0 != encoder->private_->windowed_signal_unaligned) {
+		free(encoder->private_->windowed_signal_unaligned);
+		encoder->private_->windowed_signal_unaligned = 0;
+	}
+#endif
 	for(channel = 0; channel < encoder->protected_->channels; channel++) {
 		for(i = 0; i < 2; i++) {
 			if(0 != encoder->private_->residual_workspace_unaligned[channel][i]) {
@@ -1531,10 +2381,6 @@
 			}
 		}
 	}
-	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;
@@ -1551,60 +2397,143 @@
 			}
 		}
 	}
-	FLAC__bitbuffer_free(encoder->private_->frame);
+	FLAC__bitwriter_free(encoder->private_->frame);
 }
 
-FLAC__bool resize_buffers_(FLAC__StreamEncoder *encoder, unsigned new_size)
+FLAC__bool resize_buffers_(FLAC__StreamEncoder *encoder, unsigned new_blocksize)
 {
 	FLAC__bool ok;
 	unsigned i, channel;
 
-	FLAC__ASSERT(new_size > 0);
+	FLAC__ASSERT(new_blocksize > 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)
+	if(new_blocksize <= 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)
+	/* WATCHOUT: FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32_mmx() and ..._intrin_sse2()
+	 * require 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.
+	 * alignment purposes; we use 4 in front 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]);
+		ok = ok && FLAC__memory_alloc_aligned_int32_array(new_blocksize+4+OVERREAD_, &encoder->private_->integer_signal_unaligned[i], &encoder->private_->integer_signal[i]);
 		memset(encoder->private_->integer_signal[i], 0, sizeof(FLAC__int32)*4);
 		encoder->private_->integer_signal[i] += 4;
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+#if 0 /* @@@ currently unused */
+		if(encoder->protected_->max_lpc_order > 0)
+			ok = ok && FLAC__memory_alloc_aligned_real_array(new_blocksize+OVERREAD_, &encoder->private_->real_signal_unaligned[i], &encoder->private_->real_signal[i]);
+#endif
+#endif
 	}
 	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]);
+		ok = ok && FLAC__memory_alloc_aligned_int32_array(new_blocksize+4+OVERREAD_, &encoder->private_->integer_signal_mid_side_unaligned[i], &encoder->private_->integer_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;
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+#if 0 /* @@@ currently unused */
+		if(encoder->protected_->max_lpc_order > 0)
+			ok = ok && FLAC__memory_alloc_aligned_real_array(new_blocksize+OVERREAD_, &encoder->private_->real_signal_mid_side_unaligned[i], &encoder->private_->real_signal_mid_side[i]);
+#endif
+#endif
 	}
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+	if(ok && encoder->protected_->max_lpc_order > 0) {
+		for(i = 0; ok && i < encoder->protected_->num_apodizations; i++)
+			ok = ok && FLAC__memory_alloc_aligned_real_array(new_blocksize, &encoder->private_->window_unaligned[i], &encoder->private_->window[i]);
+		ok = ok && FLAC__memory_alloc_aligned_real_array(new_blocksize, &encoder->private_->windowed_signal_unaligned, &encoder->private_->windowed_signal);
+	}
+#endif
 	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]);
+			ok = ok && FLAC__memory_alloc_aligned_int32_array(new_blocksize, &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_int32_array(new_blocksize, &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);
+	/* the *2 is an approximation to the series 1 + 1/2 + 1/4 + ... that sums tree occupies in a flat array */
+	/*@@@ new_blocksize*2 is too pessimistic, but to fix, we need smarter logic because a smaller new_blocksize can actually increase the # of partitions; would require moving this out into a separate function, then checking its capacity against the need of the current blocksize&min/max_partition_order (and maybe predictor order) */
+	ok = ok && FLAC__memory_alloc_aligned_uint64_array(new_blocksize * 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);
+		ok = ok && FLAC__memory_alloc_aligned_unsigned_array(new_blocksize * 2, &encoder->private_->raw_bits_per_partition_unaligned, &encoder->private_->raw_bits_per_partition);
 
+	/* now adjust the windows if the blocksize has changed */
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+	if(ok && new_blocksize != encoder->private_->input_capacity && encoder->protected_->max_lpc_order > 0) {
+		for(i = 0; ok && i < encoder->protected_->num_apodizations; i++) {
+			switch(encoder->protected_->apodizations[i].type) {
+				case FLAC__APODIZATION_BARTLETT:
+					FLAC__window_bartlett(encoder->private_->window[i], new_blocksize);
+					break;
+				case FLAC__APODIZATION_BARTLETT_HANN:
+					FLAC__window_bartlett_hann(encoder->private_->window[i], new_blocksize);
+					break;
+				case FLAC__APODIZATION_BLACKMAN:
+					FLAC__window_blackman(encoder->private_->window[i], new_blocksize);
+					break;
+				case FLAC__APODIZATION_BLACKMAN_HARRIS_4TERM_92DB_SIDELOBE:
+					FLAC__window_blackman_harris_4term_92db_sidelobe(encoder->private_->window[i], new_blocksize);
+					break;
+				case FLAC__APODIZATION_CONNES:
+					FLAC__window_connes(encoder->private_->window[i], new_blocksize);
+					break;
+				case FLAC__APODIZATION_FLATTOP:
+					FLAC__window_flattop(encoder->private_->window[i], new_blocksize);
+					break;
+				case FLAC__APODIZATION_GAUSS:
+					FLAC__window_gauss(encoder->private_->window[i], new_blocksize, encoder->protected_->apodizations[i].parameters.gauss.stddev);
+					break;
+				case FLAC__APODIZATION_HAMMING:
+					FLAC__window_hamming(encoder->private_->window[i], new_blocksize);
+					break;
+				case FLAC__APODIZATION_HANN:
+					FLAC__window_hann(encoder->private_->window[i], new_blocksize);
+					break;
+				case FLAC__APODIZATION_KAISER_BESSEL:
+					FLAC__window_kaiser_bessel(encoder->private_->window[i], new_blocksize);
+					break;
+				case FLAC__APODIZATION_NUTTALL:
+					FLAC__window_nuttall(encoder->private_->window[i], new_blocksize);
+					break;
+				case FLAC__APODIZATION_RECTANGLE:
+					FLAC__window_rectangle(encoder->private_->window[i], new_blocksize);
+					break;
+				case FLAC__APODIZATION_TRIANGLE:
+					FLAC__window_triangle(encoder->private_->window[i], new_blocksize);
+					break;
+				case FLAC__APODIZATION_TUKEY:
+					FLAC__window_tukey(encoder->private_->window[i], new_blocksize, encoder->protected_->apodizations[i].parameters.tukey.p);
+					break;
+				case FLAC__APODIZATION_PARTIAL_TUKEY:
+					FLAC__window_partial_tukey(encoder->private_->window[i], new_blocksize, encoder->protected_->apodizations[i].parameters.multiple_tukey.p, encoder->protected_->apodizations[i].parameters.multiple_tukey.start, encoder->protected_->apodizations[i].parameters.multiple_tukey.end);
+					break;
+				case FLAC__APODIZATION_PUNCHOUT_TUKEY:
+					FLAC__window_punchout_tukey(encoder->private_->window[i], new_blocksize, encoder->protected_->apodizations[i].parameters.multiple_tukey.p, encoder->protected_->apodizations[i].parameters.multiple_tukey.start, encoder->protected_->apodizations[i].parameters.multiple_tukey.end);
+					break;
+				case FLAC__APODIZATION_WELCH:
+					FLAC__window_welch(encoder->private_->window[i], new_blocksize);
+					break;
+				default:
+					FLAC__ASSERT(0);
+					/* double protection */
+					FLAC__window_hann(encoder->private_->window[i], new_blocksize);
+					break;
+			}
+		}
+	}
+#endif
+
 	if(ok)
-		encoder->private_->input_capacity = new_size;
+		encoder->private_->input_capacity = new_blocksize;
 	else
 		encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR;
 
@@ -1611,14 +2540,17 @@
 	return ok;
 }
 
-FLAC__bool write_bitbuffer_(FLAC__StreamEncoder *encoder, unsigned samples)
+FLAC__bool write_bitbuffer_(FLAC__StreamEncoder *encoder, unsigned samples, FLAC__bool is_last_block)
 {
 	const FLAC__byte *buffer;
-	unsigned bytes;
+	size_t bytes;
 
-	FLAC__ASSERT(FLAC__bitbuffer_is_byte_aligned(encoder->private_->frame));
+	FLAC__ASSERT(FLAC__bitwriter_is_byte_aligned(encoder->private_->frame));
 
-	FLAC__bitbuffer_get_buffer(encoder->private_->frame, &buffer, &bytes);
+	if(!FLAC__bitwriter_get_buffer(encoder->private_->frame, &buffer, &bytes)) {
+		encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR;
+		return false;
+	}
 
 	if(encoder->protected_->verify) {
 		encoder->private_->verify.output.data = buffer;
@@ -1628,7 +2560,8 @@
 		}
 		else {
 			if(!FLAC__stream_decoder_process_single(encoder->private_->verify.decoder)) {
-				FLAC__bitbuffer_release_buffer(encoder->private_->frame);
+				FLAC__bitwriter_release_buffer(encoder->private_->frame);
+				FLAC__bitwriter_clear(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;
@@ -1636,30 +2569,472 @@
 		}
 	}
 
-	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;
+	if(write_frame_(encoder, buffer, bytes, samples, is_last_block) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) {
+		FLAC__bitwriter_release_buffer(encoder->private_->frame);
+		FLAC__bitwriter_clear(encoder->private_->frame);
+		encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
 		return false;
 	}
 
-	FLAC__bitbuffer_release_buffer(encoder->private_->frame);
+	FLAC__bitwriter_release_buffer(encoder->private_->frame);
+	FLAC__bitwriter_clear(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);
+		encoder->private_->streaminfo.data.stream_info.min_framesize = flac_min(bytes, encoder->private_->streaminfo.data.stream_info.min_framesize);
+		encoder->private_->streaminfo.data.stream_info.max_framesize = flac_max(bytes, encoder->private_->streaminfo.data.stream_info.max_framesize);
 	}
 
 	return true;
 }
 
-FLAC__bool process_frame_(FLAC__StreamEncoder *encoder, FLAC__bool is_last_frame)
+FLAC__StreamEncoderWriteStatus write_frame_(FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples, FLAC__bool is_last_block)
 {
+	FLAC__StreamEncoderWriteStatus status;
+	FLAC__uint64 output_position = 0;
+
+#if FLAC__HAS_OGG == 0
+	(void)is_last_block;
+#endif
+
+	/* FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED just means we didn't get the offset; no error */
+	if(encoder->private_->tell_callback && encoder->private_->tell_callback(encoder, &output_position, encoder->private_->client_data) == FLAC__STREAM_ENCODER_TELL_STATUS_ERROR) {
+		encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
+		return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_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);
+		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++;
+			}
+		}
+	}
+
+#if FLAC__HAS_OGG
+	if(encoder->private_->is_ogg) {
+		status = FLAC__ogg_encoder_aspect_write_callback_wrapper(
+			&encoder->protected_->ogg_encoder_aspect,
+			buffer,
+			bytes,
+			samples,
+			encoder->private_->current_frame_number,
+			is_last_block,
+			(FLAC__OggEncoderAspectWriteCallbackProxy)encoder->private_->write_callback,
+			encoder,
+			encoder->private_->client_data
+		);
+	}
+	else
+#endif
+	status = encoder->private_->write_callback(encoder, buffer, bytes, samples, encoder->private_->current_frame_number, encoder->private_->client_data);
+
+	if(status == FLAC__STREAM_ENCODER_WRITE_STATUS_OK) {
+		encoder->private_->bytes_written += bytes;
+		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.
+		 */
+		encoder->private_->frames_written = flac_max(encoder->private_->frames_written, encoder->private_->current_frame_number+1);
+	}
+	else
+		encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
+
+	return status;
+}
+
+/* Gets called when the encoding process has finished so that we can update the STREAMINFO and SEEKTABLE blocks.  */
+void update_metadata_(const FLAC__StreamEncoder *encoder)
+{
+	FLAC__byte b[flac_max(6u, FLAC__STREAM_METADATA_SEEKPOINT_LENGTH)];
+	const FLAC__StreamMetadata *metadata = &encoder->private_->streaminfo;
+	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__StreamEncoderSeekStatus seek_status;
+
+	FLAC__ASSERT(metadata->type == FLAC__METADATA_TYPE_STREAMINFO);
+
+	/* 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((seek_status = encoder->private_->seek_callback(encoder, encoder->protected_->streaminfo_offset + md5_offset, encoder->private_->client_data)) != FLAC__STREAM_ENCODER_SEEK_STATUS_OK) {
+			if(seek_status == FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR)
+				encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_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__STREAM_ENCODER_CLIENT_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((seek_status = encoder->private_->seek_callback(encoder, encoder->protected_->streaminfo_offset + total_samples_byte_offset, encoder->private_->client_data)) != FLAC__STREAM_ENCODER_SEEK_STATUS_OK) {
+			if(seek_status == FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR)
+				encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_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__STREAM_ENCODER_CLIENT_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((seek_status = encoder->private_->seek_callback(encoder, encoder->protected_->streaminfo_offset + min_framesize_offset, encoder->private_->client_data)) != FLAC__STREAM_ENCODER_SEEK_STATUS_OK) {
+			if(seek_status == FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR)
+				encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_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__STREAM_ENCODER_CLIENT_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((seek_status = encoder->private_->seek_callback(encoder, encoder->protected_->seektable_offset + FLAC__STREAM_METADATA_HEADER_LENGTH, encoder->private_->client_data)) != FLAC__STREAM_ENCODER_SEEK_STATUS_OK) {
+			if(seek_status == FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR)
+				encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_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__STREAM_ENCODER_CLIENT_ERROR;
+				return;
+			}
+		}
+	}
+}
+
+#if FLAC__HAS_OGG
+/* Gets called when the encoding process has finished so that we can update the STREAMINFO and SEEKTABLE blocks.  */
+void update_ogg_metadata_(FLAC__StreamEncoder *encoder)
+{
+	/* the # of bytes in the 1st packet that precede the STREAMINFO */
+	static const unsigned FIRST_OGG_PACKET_STREAMINFO_PREFIX_LENGTH =
+		FLAC__OGG_MAPPING_PACKET_TYPE_LENGTH +
+		FLAC__OGG_MAPPING_MAGIC_LENGTH +
+		FLAC__OGG_MAPPING_VERSION_MAJOR_LENGTH +
+		FLAC__OGG_MAPPING_VERSION_MINOR_LENGTH +
+		FLAC__OGG_MAPPING_NUM_HEADERS_LENGTH +
+		FLAC__STREAM_SYNC_LENGTH
+	;
+	FLAC__byte b[flac_max(6u, FLAC__STREAM_METADATA_SEEKPOINT_LENGTH)];
+	const FLAC__StreamMetadata *metadata = &encoder->private_->streaminfo;
+	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;
+	ogg_page page;
+
+	FLAC__ASSERT(metadata->type == FLAC__METADATA_TYPE_STREAMINFO);
+	FLAC__ASSERT(0 != encoder->private_->seek_callback);
+
+	/* Pre-check that client supports seeking, since we don't want the
+	 * ogg_helper code to ever have to deal with this condition.
+	 */
+	if(encoder->private_->seek_callback(encoder, 0, encoder->private_->client_data) == FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED)
+		return;
+
+	/* All this is based on intimate knowledge of the stream header
+	 * layout, but a change to the header format that would break this
+	 * would also break all streams encoded in the previous format.
+	 */
+
+	/**
+	 ** Write STREAMINFO stats
+	 **/
+	simple_ogg_page__init(&page);
+	if(!simple_ogg_page__get_at(encoder, encoder->protected_->streaminfo_offset, &page, encoder->private_->seek_callback, encoder->private_->read_callback, encoder->private_->client_data)) {
+		simple_ogg_page__clear(&page);
+		return; /* state already set */
+	}
+
+	/*
+	 * Write MD5 signature
+	 */
+	{
+		const unsigned md5_offset =
+			FIRST_OGG_PACKET_STREAMINFO_PREFIX_LENGTH +
+			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(md5_offset + 16 > (unsigned)page.body_len) {
+			encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR;
+			simple_ogg_page__clear(&page);
+			return;
+		}
+		memcpy(page.body + md5_offset, metadata->data.stream_info.md5sum, 16);
+	}
+
+	/*
+	 * Write total samples
+	 */
+	{
+		const unsigned total_samples_byte_offset =
+			FIRST_OGG_PACKET_STREAMINFO_PREFIX_LENGTH +
+			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;
+
+		if(total_samples_byte_offset + 5 > (unsigned)page.body_len) {
+			encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR;
+			simple_ogg_page__clear(&page);
+			return;
+		}
+		b[0] = (FLAC__byte)page.body[total_samples_byte_offset] & 0xF0;
+		b[0] |= (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);
+		memcpy(page.body + total_samples_byte_offset, b, 5);
+	}
+
+	/*
+	 * Write min/max framesize
+	 */
+	{
+		const unsigned min_framesize_offset =
+			FIRST_OGG_PACKET_STREAMINFO_PREFIX_LENGTH +
+			FLAC__STREAM_METADATA_HEADER_LENGTH +
+			(
+				FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN +
+				FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN
+			) / 8;
+
+		if(min_framesize_offset + 6 > (unsigned)page.body_len) {
+			encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR;
+			simple_ogg_page__clear(&page);
+			return;
+		}
+		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);
+		memcpy(page.body + min_framesize_offset, b, 6);
+	}
+	if(!simple_ogg_page__set_at(encoder, encoder->protected_->streaminfo_offset, &page, encoder->private_->seek_callback, encoder->private_->write_callback, encoder->private_->client_data)) {
+		simple_ogg_page__clear(&page);
+		return; /* state already set */
+	}
+	simple_ogg_page__clear(&page);
+
+	/*
+	 * Write seektable
+	 */
+	if(0 != encoder->private_->seek_table && encoder->private_->seek_table->num_points > 0 && encoder->protected_->seektable_offset > 0) {
+		unsigned i;
+		FLAC__byte *p;
+
+		FLAC__format_seektable_sort(encoder->private_->seek_table);
+
+		FLAC__ASSERT(FLAC__format_seektable_is_legal(encoder->private_->seek_table));
+
+		simple_ogg_page__init(&page);
+		if(!simple_ogg_page__get_at(encoder, encoder->protected_->seektable_offset, &page, encoder->private_->seek_callback, encoder->private_->read_callback, encoder->private_->client_data)) {
+			simple_ogg_page__clear(&page);
+			return; /* state already set */
+		}
+
+		if((FLAC__STREAM_METADATA_HEADER_LENGTH + 18*encoder->private_->seek_table->num_points) != (unsigned)page.body_len) {
+			encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR;
+			simple_ogg_page__clear(&page);
+			return;
+		}
+
+		for(i = 0, p = page.body + FLAC__STREAM_METADATA_HEADER_LENGTH; i < encoder->private_->seek_table->num_points; i++, p += 18) {
+			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;
+			memcpy(p, b, 18);
+		}
+
+		if(!simple_ogg_page__set_at(encoder, encoder->protected_->seektable_offset, &page, encoder->private_->seek_callback, encoder->private_->write_callback, encoder->private_->client_data)) {
+			simple_ogg_page__clear(&page);
+			return; /* state already set */
+		}
+		simple_ogg_page__clear(&page);
+	}
+}
+#endif
+
+FLAC__bool process_frame_(FLAC__StreamEncoder *encoder, FLAC__bool is_fractional_block, FLAC__bool is_last_block)
+{
+	FLAC__uint16 crc;
 	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)) {
+	if(encoder->protected_->do_md5 && !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;
 	}
@@ -1667,7 +3042,7 @@
 	/*
 	 * Process the frame header and subframes into the frame bitbuffer
 	 */
-	if(!process_subframes_(encoder, is_last_frame)) {
+	if(!process_subframes_(encoder, is_fractional_block)) {
 		/* the above function sets the state for us in case of an error */
 		return false;
 	}
@@ -1675,7 +3050,7 @@
 	/*
 	 * Zero-pad the frame to a byte_boundary
 	 */
-	if(!FLAC__bitbuffer_zero_pad_to_byte_boundary(encoder->private_->frame)) {
+	if(!FLAC__bitwriter_zero_pad_to_byte_boundary(encoder->private_->frame)) {
 		encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR;
 		return false;
 	}
@@ -1683,13 +3058,19 @@
 	/*
 	 * 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);
+	FLAC__ASSERT(FLAC__bitwriter_is_byte_aligned(encoder->private_->frame));
+	if(
+		!FLAC__bitwriter_get_write_crc16(encoder->private_->frame, &crc) ||
+		!FLAC__bitwriter_write_raw_uint32(encoder->private_->frame, crc, FLAC__FRAME_FOOTER_CRC_LEN)
+	) {
+		encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR;
+		return false;
+	}
 
 	/*
 	 * Write it
 	 */
-	if(!write_bitbuffer_(encoder, encoder->protected_->blocksize)) {
+	if(!write_bitbuffer_(encoder, encoder->protected_->blocksize, is_last_block)) {
 		/* the above function sets the state for us in case of an error */
 		return false;
 	}
@@ -1699,38 +3080,32 @@
 	 */
 	encoder->private_->current_sample_number = 0;
 	encoder->private_->current_frame_number++;
-	encoder->private_->metadata.data.stream_info.total_samples += (FLAC__uint64)encoder->protected_->blocksize;
+	encoder->private_->streaminfo.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__bool process_subframes_(FLAC__StreamEncoder *encoder, FLAC__bool is_fractional_block)
 {
 	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;
+	FLAC__bool do_independent, do_mid_side;
 
 	/*
 	 * Calculate the min,max Rice partition orders
 	 */
-	if(is_last_frame) {
+	if(is_fractional_block) {
 		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);
+		max_partition_order = flac_min(max_partition_order, encoder->protected_->max_residual_partition_order);
 	}
-	min_partition_order = min(min_partition_order, max_partition_order);
+	min_partition_order = flac_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;
@@ -1794,11 +3169,9 @@
 					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],
@@ -1822,11 +3195,9 @@
 					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],
@@ -1854,8 +3225,12 @@
 		else {
 			unsigned bits[4]; /* WATCHOUT - indexed by FLAC__ChannelAssignment */
 			unsigned min_bits;
-			FLAC__ChannelAssignment ca;
+			int ca;
 
+			FLAC__ASSERT(FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT == 0);
+			FLAC__ASSERT(FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE   == 1);
+			FLAC__ASSERT(FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE  == 2);
+			FLAC__ASSERT(FLAC__CHANNEL_ASSIGNMENT_MID_SIDE    == 3);
 			FLAC__ASSERT(do_independent && do_mid_side);
 
 			/* We have to figure out which channel assignent results in the smallest frame */
@@ -1864,10 +3239,12 @@
 			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)) {
+			channel_assignment = FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT;
+			min_bits = bits[channel_assignment];
+			for(ca = 1; ca <= 3; ca++) {
 				if(bits[ca] < min_bits) {
 					min_bits = bits[ca];
-					channel_assignment = ca;
+					channel_assignment = (FLAC__ChannelAssignment)ca;
 				}
 			}
 		}
@@ -1874,7 +3251,7 @@
 
 		frame_header.channel_assignment = channel_assignment;
 
-		if(!FLAC__frame_add_header(&frame_header, encoder->protected_->streamable_subset, encoder->private_->frame)) {
+		if(!FLAC__frame_add_header(&frame_header, encoder->private_->frame)) {
 			encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR;
 			return false;
 		}
@@ -1922,19 +3299,19 @@
 		}
 
 		/* 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))
+		if(!add_subframe_(encoder, frame_header.blocksize, left_bps , left_subframe , encoder->private_->frame))
 			return false;
-		if(!add_subframe_(encoder, &frame_header, right_bps, right_subframe, encoder->private_->frame))
+		if(!add_subframe_(encoder, frame_header.blocksize, right_bps, right_subframe, encoder->private_->frame))
 			return false;
 	}
 	else {
-		if(!FLAC__frame_add_header(&frame_header, encoder->protected_->streamable_subset, encoder->private_->frame)) {
+		if(!FLAC__frame_add_header(&frame_header, 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)) {
+			if(!add_subframe_(encoder, frame_header.blocksize, 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;
 			}
@@ -1956,11 +3333,9 @@
 	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],
@@ -1968,33 +3343,50 @@
 	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];
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+	FLAC__float fixed_residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1];
+#else
+	FLAC__fixedpoint fixed_residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1];
+#endif
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+	FLAC__double 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 and x86 intrinsic routines need all the space */
+	FLAC__double 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;
+#endif
+	unsigned min_fixed_order, max_fixed_order, guess_fixed_order, fixed_order;
 	unsigned rice_parameter;
 	unsigned _candidate_bits, _best_bits;
 	unsigned _best_subframe;
+	/* only use RICE2 partitions if stream bps > 16 */
+	const unsigned rice_parameter_limit = FLAC__stream_encoder_get_bits_per_sample(encoder) > 16? FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER : FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER;
 
+	FLAC__ASSERT(frame_header->blocksize > 0);
+
 	/* 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]);
+		_best_bits = evaluate_verbatim_subframe_(encoder, 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 */
+		if(
+			!encoder->private_->disable_constant_subframes &&
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+			fixed_residual_bits_per_sample[1] == 0.0
+#else
+			fixed_residual_bits_per_sample[1] == FLAC__FP_ZERO
+#endif
+		) {
+			/* the above means it's possible all samples are the same value; now double-check it: */
 			unsigned i;
 			signal_is_constant = true;
-			for(i = 1; i <= FLAC__MAX_FIXED_ORDER; i++) {
+			for(i = 1; i < frame_header->blocksize; i++) {
 				if(integer_signal[0] != integer_signal[i]) {
 					signal_is_constant = false;
 					break;
@@ -2002,7 +3394,7 @@
 			}
 		}
 		if(signal_is_constant) {
-			_candidate_bits = evaluate_constant_subframe_(integer_signal[0], subframe_bps, subframe[!_best_subframe]);
+			_candidate_bits = evaluate_constant_subframe_(encoder, integer_signal[0], frame_header->blocksize, subframe_bps, subframe[!_best_subframe]);
 			if(_candidate_bits < _best_bits) {
 				_best_subframe = !_best_subframe;
 				_best_bits = _candidate_bits;
@@ -2018,18 +3410,24 @@
 				else {
 					min_fixed_order = max_fixed_order = guess_fixed_order;
 				}
+				if(max_fixed_order >= frame_header->blocksize)
+					max_fixed_order = frame_header->blocksize - 1;
 				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)
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+					if(fixed_residual_bits_per_sample[fixed_order] >= (FLAC__float)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 */
+#else
+					if(FLAC__fixedpoint_trunc(fixed_residual_bits_per_sample[fixed_order]) >= (int)subframe_bps)
+						continue; /* don't even try */
+					rice_parameter = (fixed_residual_bits_per_sample[fixed_order] > FLAC__FP_ZERO)? (unsigned)FLAC__fixedpoint_trunc(fixed_residual_bits_per_sample[fixed_order]+FLAC__FP_ONE_HALF) : 0; /* 0.5 is for rounding */
 #endif
-					if(rice_parameter >= FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER) {
+					rice_parameter++; /* to account for the signed->unsigned conversion during rice coding */
+					if(rice_parameter >= rice_parameter_limit) {
 #ifdef DEBUG_VERBOSE
-						fprintf(stderr, "clipping rice_parameter (%u -> %u) @0\n", rice_parameter, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1);
+						fprintf(stderr, "clipping rice_parameter (%u -> %u) @0\n", rice_parameter, rice_parameter_limit - 1);
 #endif
-						rice_parameter = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1;
+						rice_parameter = rice_parameter_limit - 1;
 					}
 					_candidate_bits =
 						evaluate_fixed_subframe_(
@@ -2036,7 +3434,6 @@
 							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,
@@ -2043,9 +3440,9 @@
 							subframe_bps,
 							fixed_order,
 							rice_parameter,
+							rice_parameter_limit,
 							min_partition_order,
 							max_partition_order,
-							precompute_partition_sums,
 							encoder->protected_->do_escape_coding,
 							encoder->protected_->rice_parameter_search_dist,
 							subframe[!_best_subframe],
@@ -2058,6 +3455,7 @@
 				}
 			}
 
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
 			/* encode lpc */
 			if(encoder->protected_->max_lpc_order > 0) {
 				if(encoder->protected_->max_lpc_order >= frame_header->blocksize)
@@ -2065,76 +3463,92 @@
 				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;
+					unsigned a;
+					for (a = 0; a < encoder->protected_->num_apodizations; a++) {
+						FLAC__lpc_window_data(integer_signal, encoder->private_->window[a], encoder->private_->windowed_signal, frame_header->blocksize);
+						encoder->private_->local_lpc_compute_autocorrelation(encoder->private_->windowed_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;
 							}
-							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],
+								const unsigned guess_lpc_order =
+									FLAC__lpc_compute_best_order(
+										lpc_error,
+										max_lpc_order,
 										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]
+										subframe_bps + (
+											encoder->protected_->do_qlp_coeff_prec_search?
+												FLAC__MIN_QLP_COEFF_PRECISION : /* have to guess; use the min possible size to avoid accidentally favoring lower orders */
+												encoder->protected_->qlp_coeff_precision
+										)
 									);
-								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;
+								min_lpc_order = max_lpc_order = guess_lpc_order;
+							}
+							if(max_lpc_order >= frame_header->blocksize)
+								max_lpc_order = frame_header->blocksize - 1;
+							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__double)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 */
+								rice_parameter++; /* to account for the signed->unsigned conversion during rice coding */
+								if(rice_parameter >= rice_parameter_limit) {
+#ifdef DEBUG_VERBOSE
+									fprintf(stderr, "clipping rice_parameter (%u -> %u) @1\n", rice_parameter, rice_parameter_limit - 1);
+#endif
+									rice_parameter = rice_parameter_limit - 1;
+								}
+								if(encoder->protected_->do_qlp_coeff_prec_search) {
+									min_qlp_coeff_precision = FLAC__MIN_QLP_COEFF_PRECISION;
+									/* try to keep qlp coeff precision such that only 32-bit math is required for decode of <=16bps streams */
+									if(subframe_bps <= 16) {
+										max_qlp_coeff_precision = flac_min(32 - subframe_bps - FLAC__bitmath_ilog2(lpc_order), FLAC__MAX_QLP_COEFF_PRECISION);
+										max_qlp_coeff_precision = flac_max(max_qlp_coeff_precision, min_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_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,
+											rice_parameter_limit,
+											min_partition_order,
+											max_partition_order,
+											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;
+										}
+									}
+								}
 							}
 						}
 					}
 				}
 			}
+#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */
 		}
 	}
 
@@ -2141,7 +3555,7 @@
 	/* 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_bits = evaluate_verbatim_subframe_(encoder, integer_signal, frame_header->blocksize, subframe_bps, subframe[_best_subframe]);
 	}
 
 	*best_subframe = _best_subframe;
@@ -2152,34 +3566,34 @@
 
 FLAC__bool add_subframe_(
 	FLAC__StreamEncoder *encoder,
-	const FLAC__FrameHeader *frame_header,
+	unsigned blocksize,
 	unsigned subframe_bps,
 	const FLAC__Subframe *subframe,
-	FLAC__BitBuffer *frame
+	FLAC__BitWriter *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;
+				encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR;
 				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;
+			if(!FLAC__subframe_add_fixed(&(subframe->data.fixed), blocksize - subframe->data.fixed.order, subframe_bps, subframe->wasted_bits, frame)) {
+				encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR;
 				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;
+			if(!FLAC__subframe_add_lpc(&(subframe->data.lpc), blocksize - subframe->data.lpc.order, subframe_bps, subframe->wasted_bits, frame)) {
+				encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR;
 				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;
+			if(!FLAC__subframe_add_verbatim(&(subframe->data.verbatim), blocksize, subframe_bps, subframe->wasted_bits, frame)) {
+				encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR;
 				return false;
 			}
 			break;
@@ -2190,16 +3604,58 @@
 	return true;
 }
 
+#define SPOTCHECK_ESTIMATE 0
+#if SPOTCHECK_ESTIMATE
+static void spotcheck_subframe_estimate_(
+	FLAC__StreamEncoder *encoder,
+	unsigned blocksize,
+	unsigned subframe_bps,
+	const FLAC__Subframe *subframe,
+	unsigned estimate
+)
+{
+	FLAC__bool ret;
+	FLAC__BitWriter *frame = FLAC__bitwriter_new();
+	if(frame == 0) {
+		fprintf(stderr, "EST: can't allocate frame\n");
+		return;
+	}
+	if(!FLAC__bitwriter_init(frame)) {
+		fprintf(stderr, "EST: can't init frame\n");
+		return;
+	}
+	ret = add_subframe_(encoder, blocksize, subframe_bps, subframe, frame);
+	FLAC__ASSERT(ret);
+	{
+		const unsigned actual = FLAC__bitwriter_get_input_bits_unconsumed(frame);
+		if(estimate != actual)
+			fprintf(stderr, "EST: bad, frame#%u sub#%%d type=%8s est=%u, actual=%u, delta=%d\n", encoder->private_->current_frame_number, FLAC__SubframeTypeString[subframe->type], estimate, actual, (int)actual-(int)estimate);
+	}
+	FLAC__bitwriter_delete(frame);
+}
+#endif
+
 unsigned evaluate_constant_subframe_(
+	FLAC__StreamEncoder *encoder,
 	const FLAC__int32 signal,
+	unsigned blocksize,
 	unsigned subframe_bps,
 	FLAC__Subframe *subframe
 )
 {
+	unsigned estimate;
 	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;
+	estimate = FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN + subframe->wasted_bits + subframe_bps;
+
+#if SPOTCHECK_ESTIMATE
+	spotcheck_subframe_estimate_(encoder, blocksize, subframe_bps, subframe, estimate);
+#else
+	(void)encoder, (void)blocksize;
+#endif
+
+	return estimate;
 }
 
 unsigned evaluate_fixed_subframe_(
@@ -2206,7 +3662,6 @@
 	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,
@@ -2213,9 +3668,9 @@
 	unsigned subframe_bps,
 	unsigned order,
 	unsigned rice_parameter,
+	unsigned rice_parameter_limit,
 	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,
@@ -2222,7 +3677,7 @@
 	FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents
 )
 {
-	unsigned i, residual_bits;
+	unsigned i, residual_bits, estimate;
 	const unsigned residual_samples = blocksize - order;
 
 	FLAC__fixed_compute_residual(signal+order, residual_samples, order, residual);
@@ -2237,18 +3692,18 @@
 		find_best_partition_order_(
 			encoder->private_,
 			residual,
-			abs_residual,
 			abs_residual_partition_sums,
 			raw_bits_per_partition,
 			residual_samples,
 			order,
 			rice_parameter,
+			rice_parameter_limit,
 			min_partition_order,
 			max_partition_order,
-			precompute_partition_sums,
+			subframe_bps,
 			do_escape_coding,
 			rice_parameter_search_dist,
-			&subframe->data.fixed.entropy_coding_method.data.partitioned_rice
+			&subframe->data.fixed.entropy_coding_method
 		);
 
 	subframe->data.fixed.order = order;
@@ -2255,14 +3710,20 @@
 	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;
+	estimate = FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN + subframe->wasted_bits + (order * subframe_bps) + residual_bits;
+
+#if SPOTCHECK_ESTIMATE
+	spotcheck_subframe_estimate_(encoder, blocksize, subframe_bps, subframe, estimate);
+#endif
+
+	return estimate;
 }
 
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
 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[],
@@ -2271,9 +3732,9 @@
 	unsigned order,
 	unsigned qlp_coeff_precision,
 	unsigned rice_parameter,
+	unsigned rice_parameter_limit,
 	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,
@@ -2280,8 +3741,8 @@
 	FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents
 )
 {
-	FLAC__int32 qlp_coeff[FLAC__MAX_LPC_ORDER];
-	unsigned i, residual_bits;
+	FLAC__int32 qlp_coeff[FLAC__MAX_LPC_ORDER]; /* WATCHOUT: the size is important; some x86 intrinsic routines need more than lpc order elements */
+	unsigned i, residual_bits, estimate;
 	int quantization, ret;
 	const unsigned residual_samples = blocksize - order;
 
@@ -2289,7 +3750,7 @@
 	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));
+		qlp_coeff_precision = flac_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);
@@ -2314,18 +3775,18 @@
 		find_best_partition_order_(
 			encoder->private_,
 			residual,
-			abs_residual,
 			abs_residual_partition_sums,
 			raw_bits_per_partition,
 			residual_samples,
 			order,
 			rice_parameter,
+			rice_parameter_limit,
 			min_partition_order,
 			max_partition_order,
-			precompute_partition_sums,
+			subframe_bps,
 			do_escape_coding,
 			rice_parameter_search_dist,
-			&subframe->data.fixed.entropy_coding_method.data.partitioned_rice
+			&subframe->data.lpc.entropy_coding_method
 		);
 
 	subframe->data.lpc.order = order;
@@ -2335,10 +3796,18 @@
 	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;
+	estimate = FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN + subframe->wasted_bits + FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN + FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN + (order * (qlp_coeff_precision + subframe_bps)) + residual_bits;
+
+#if SPOTCHECK_ESTIMATE
+	spotcheck_subframe_estimate_(encoder, blocksize, subframe_bps, subframe, estimate);
+#endif
+
+	return estimate;
 }
+#endif
 
 unsigned evaluate_verbatim_subframe_(
+	FLAC__StreamEncoder *encoder,
 	const FLAC__int32 signal[],
 	unsigned blocksize,
 	unsigned subframe_bps,
@@ -2345,64 +3814,69 @@
 	FLAC__Subframe *subframe
 )
 {
+	unsigned estimate;
+
 	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);
+	estimate = FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN + subframe->wasted_bits + (blocksize * subframe_bps);
+
+#if SPOTCHECK_ESTIMATE
+	spotcheck_subframe_estimate_(encoder, blocksize, subframe_bps, subframe, estimate);
+#else
+	(void)encoder;
+#endif
+
+	return estimate;
 }
 
 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 rice_parameter_limit,
 	unsigned min_partition_order,
 	unsigned max_partition_order,
-	FLAC__bool precompute_partition_sums,
+	unsigned bps,
 	FLAC__bool do_escape_coding,
 	unsigned rice_parameter_search_dist,
-	FLAC__EntropyCodingMethod_PartitionedRice *best_partitioned_rice
+	FLAC__EntropyCodingMethod *best_ecm
 )
 {
-	FLAC__int32 r;
 	unsigned residual_bits, best_residual_bits = 0;
-	unsigned residual_sample;
 	unsigned best_parameters_index = 0;
+	unsigned best_partition_order = 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);
+	min_partition_order = flac_min(min_partition_order, max_partition_order);
 
-	if(precompute_partition_sums) {
+	private_->local_precompute_partition_info_sums(residual, abs_residual_partition_sums, residual_samples, predictor_order, min_partition_order, max_partition_order, bps);
+
+	if(do_escape_coding)
+		precompute_partition_info_escapes_(residual, raw_bits_per_partition, residual_samples, predictor_order, min_partition_order, max_partition_order);
+
+	{
 		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_(
+				set_partitioned_rice_(
+#ifdef EXACT_RICE_BITS_CALCULATION
 					residual,
+#endif
 					abs_residual_partition_sums+sum,
 					raw_bits_per_partition+sum,
 					residual_samples,
 					predictor_order,
 					rice_parameter,
+					rice_parameter_limit,
 					rice_parameter_search_dist,
 					(unsigned)partition_order,
 					do_escape_coding,
@@ -2410,23 +3884,6 @@
 					&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;
@@ -2435,117 +3892,99 @@
 			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;
+				best_partition_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);
+
+	best_ecm->data.partitioned_rice.order = best_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* prc = (FLAC__EntropyCodingMethod_PartitionedRiceContents*)best_ecm->data.partitioned_rice.contents;
+		unsigned partition;
+
+		/* save best parameters and raw_bits */
+		FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(prc, flac_max(6u, best_partition_order));
+		memcpy(prc->parameters, private_->partitioned_rice_contents_extra[best_parameters_index].parameters, sizeof(unsigned)*(1<<(best_partition_order)));
+		if(do_escape_coding)
+			memcpy(prc->raw_bits, private_->partitioned_rice_contents_extra[best_parameters_index].raw_bits, sizeof(unsigned)*(1<<(best_partition_order)));
+		/*
+		 * Now need to check if the type should be changed to
+		 * FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2 based on the
+		 * size of the rice parameters.
+		 */
+		for(partition = 0; partition < (1u<<best_partition_order); partition++) {
+			if(prc->parameters[partition] >= FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER) {
+				best_ecm->type = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2;
 				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[],
+	const FLAC__int32 residual[],
 	FLAC__uint64 abs_residual_partition_sums[],
 	unsigned residual_samples,
 	unsigned predictor_order,
 	unsigned min_partition_order,
-	unsigned max_partition_order
+	unsigned max_partition_order,
+	unsigned bps
 )
 {
-	int partition_order;
-	unsigned from_partition, to_partition = 0;
-	const unsigned blocksize = residual_samples + predictor_order;
+	const unsigned default_partition_samples = (residual_samples + predictor_order) >> max_partition_order;
+	unsigned partitions = 1u << max_partition_order;
 
+	FLAC__ASSERT(default_partition_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;
+	{
+		unsigned partition, residual_sample, end = (unsigned)(-(int)predictor_order);
+		/* WATCHOUT: "+ bps + FLAC__MAX_EXTRA_RESIDUAL_BPS" is the maximum
+		 * assumed size of the average residual magnitude */
+		if(FLAC__bitmath_ilog2(default_partition_samples) + bps + FLAC__MAX_EXTRA_RESIDUAL_BPS < 32) {
+			FLAC__uint32 abs_residual_partition_sum;
 
-		FLAC__ASSERT(default_partition_samples > predictor_order);
+			for(partition = residual_sample = 0; partition < partitions; partition++) {
+				end += default_partition_samples;
+				abs_residual_partition_sum = 0;
+				for( ; residual_sample < end; residual_sample++)
+					abs_residual_partition_sum += abs(residual[residual_sample]); /* abs(INT_MIN) is undefined, but if the residual is INT_MIN we have bigger problems */
+				abs_residual_partition_sums[partition] = abs_residual_partition_sum;
+			}
+		}
+		else { /* have to pessimistically use 64 bits for accumulator */
+			FLAC__uint64 abs_residual_partition_sum;
 
-		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++;
+			for(partition = residual_sample = 0; partition < partitions; partition++) {
+				end += default_partition_samples;
+				abs_residual_partition_sum = 0;
+				for( ; residual_sample < end; residual_sample++)
+					abs_residual_partition_sum += abs(residual[residual_sample]); /* abs(INT_MIN) is undefined, but if the residual is INT_MIN we have bigger problems */
+				abs_residual_partition_sums[partition] = abs_residual_partition_sum;
 			}
-			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++;
+	{
+		unsigned from_partition = 0, to_partition = partitions;
+		int partition_order;
+		for(partition_order = (int)max_partition_order - 1; partition_order >= (int)min_partition_order; partition_order--) {
+			unsigned i;
+			partitions >>= 1;
+			for(i = 0; i < partitions; i++) {
+				abs_residual_partition_sums[to_partition++] =
+					abs_residual_partition_sums[from_partition  ] +
+					abs_residual_partition_sums[from_partition+1];
+				from_partition += 2;
+			}
 		}
 	}
 }
@@ -2565,8 +4004,8 @@
 
 	/* 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;
+		FLAC__int32 r;
+		FLAC__uint32 rmax;
 		unsigned partition, partition_sample, partition_samples, residual_sample;
 		const unsigned partitions = 1u << partition_order;
 		const unsigned default_partition_samples = blocksize >> partition_order;
@@ -2577,21 +4016,20 @@
 			partition_samples = default_partition_samples;
 			if(partition == 0)
 				partition_samples -= predictor_order;
-			residual_partition_min = residual_partition_max = 0;
+			rmax = 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++;
+				r = residual[residual_sample++];
+				/* OPT: maybe faster: rmax |= r ^ (r>>31) */
+				if(r < 0)
+					rmax |= ~r;
+				else
+					rmax |= r;
 			}
-			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);
+			/* now we know all residual values are in the range [-rmax-1,rmax] */
+			raw_bits_per_partition[partition] = rmax? FLAC__bitmath_ilog2(rmax) + 2 : 1;
 		}
 		to_partition = partitions;
-		break;
+		break; /*@@@ yuck, should remove the 'for' loop instead */
 	}
 
 	/* now merge partitions for lower orders */
@@ -2602,7 +4040,7 @@
 		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]);
+			raw_bits_per_partition[to_partition] = flac_max(m, raw_bits_per_partition[from_partition]);
 			from_partition++;
 			to_partition++;
 		}
@@ -2609,216 +4047,57 @@
 	}
 }
 
-#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
+#ifdef EXACT_RICE_BITS_CALCULATION
+static inline unsigned count_rice_bits_in_partition_(
+	const unsigned rice_parameter,
+	const unsigned partition_samples,
+	const FLAC__int32 *residual
 )
+{
+	unsigned i, partition_bits =
+		FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN + /* actually could end up being FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN but err on side of 16bps */
+		(1+rice_parameter) * partition_samples /* 1 for unary stop bit + rice_parameter for the binary portion */
+	;
+	for(i = 0; i < partition_samples; i++)
+		partition_bits += ( (FLAC__uint32)((residual[i]<<1)^(residual[i]>>31)) >> rice_parameter );
+	return partition_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
+static inline unsigned count_rice_bits_in_partition_(
+	const unsigned rice_parameter,
+	const unsigned partition_samples,
+	const FLAC__uint64 abs_residual_partition_sum
 )
-#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;
+	return
+		FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN + /* actually could end up being FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN but err on side of 16bps */
+		(1+rice_parameter) * partition_samples + /* 1 for unary stop bit + rice_parameter for the binary portion */
+		(
+			rice_parameter?
+				(unsigned)(abs_residual_partition_sum >> (rice_parameter-1)) /* rice_parameter-1 because the real coder sign-folds instead of using a sign bit */
+				: (unsigned)(abs_residual_partition_sum << 1) /* can't shift by negative number, so reverse */
+		)
+		- (partition_samples >> 1)
+		/* -(partition_samples>>1) to subtract out extra contributions to the abs_residual_partition_sum.
+		 * The actual number of bits used is closer to the sum(for all i in the partition) of  abs(residual[i])>>(rice_parameter-1)
+		 * By using the abs_residual_partition sum, we also add in bits in the LSBs that would normally be shifted out.
+		 * So the subtraction term tries to guess how many extra bits were contributed.
+		 * If the LSBs are randomly distributed, this should average to 0.5 extra bits per sample.
+		 */
+	;
+}
 #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_(
+FLAC__bool set_partitioned_rice_(
+#ifdef EXACT_RICE_BITS_CALCULATION
 	const FLAC__int32 residual[],
+#endif
 	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_limit,
 	const unsigned rice_parameter_search_dist,
 	const unsigned partition_order,
 	const FLAC__bool search_for_escapes,
@@ -2825,41 +4104,27 @@
 	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 best_partition_bits, best_rice_parameter = 0;
 	unsigned bits_ = FLAC__ENTROPY_CODING_METHOD_TYPE_LEN + FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN;
 	unsigned *parameters, *raw_bits;
+#ifdef ENABLE_RICE_PARAMETER_SEARCH
+	unsigned min_rice_parameter, max_rice_parameter;
+#else
+	(void)rice_parameter_search_dist;
+#endif
 
-	FLAC__ASSERT(suggested_rice_parameter < FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER);
+	FLAC__ASSERT(suggested_rice_parameter < FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER);
+	FLAC__ASSERT(rice_parameter_limit <= FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER);
 
-	FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(partitioned_rice_contents, max(6, partition_order));
+	FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(partitioned_rice_contents, flac_max(6u, partition_order));
 	parameters = partitioned_rice_contents->parameters;
 	raw_bits = partitioned_rice_contents->raw_bits;
 
 	if(partition_order == 0) {
-		unsigned i;
-
-#ifndef NO_RICE_SEARCH
+		best_partition_bits = (unsigned)(-1);
+#ifdef ENABLE_RICE_PARAMETER_SEARCH
 		if(rice_parameter_search_dist) {
 			if(suggested_rice_parameter < rice_parameter_search_dist)
 				min_rice_parameter = 0;
@@ -2866,61 +4131,47 @@
 			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) {
+			if(max_rice_parameter >= rice_parameter_limit) {
 #ifdef DEBUG_VERBOSE
-				fprintf(stderr, "clipping rice_parameter (%u -> %u) @5\n", max_rice_parameter, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1);
+				fprintf(stderr, "clipping rice_parameter (%u -> %u) @5\n", max_rice_parameter, rice_parameter_limit - 1);
 #endif
-				max_rice_parameter = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1;
+				max_rice_parameter = rice_parameter_limit - 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;
+			rice_parameter = suggested_rice_parameter;
 #endif
+#ifdef EXACT_RICE_BITS_CALCULATION
+			partition_bits = count_rice_bits_in_partition_(rice_parameter, residual_samples, residual);
 #else
-			partition_bits = 0;
+			partition_bits = count_rice_bits_in_partition_(rice_parameter, residual_samples, abs_residual_partition_sums[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;
 			}
+#ifdef ENABLE_RICE_PARAMETER_SEARCH
 		}
 #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) {
+			partition_bits = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN + FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN + raw_bits_per_partition[0] * residual_samples;
+			if(partition_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;
+				best_rice_parameter = 0; /* will be converted to appropriate escape parameter later */
+				best_partition_bits = partition_bits;
 			}
+			else
+				raw_bits[0] = 0;
 		}
 		parameters[0] = best_rice_parameter;
 		bits_ += best_partition_bits;
 	}
 	else {
-		unsigned partition, residual_sample, save_residual_sample, partition_sample;
+		unsigned partition, residual_sample;
 		unsigned partition_samples;
 		FLAC__uint64 mean, k;
 		const unsigned partitions = 1u << partition_order;
@@ -2933,30 +4184,52 @@
 					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 */
+			/* we are basically calculating the size in bits of the
+			 * average residual magnitude in the partition:
+			 *   rice_parameter = floor(log2(mean/partition_samples))
+			 * 'mean' is not a good name for the variable, it is
+			 * actually the sum of magnitudes of all residual values
+			 * in the partition, so the actual mean is
+			 * mean/partition_samples
+			 */
+#if 0 /* old simple code */
 			for(rice_parameter = 0, k = partition_samples; k < mean; rice_parameter++, k <<= 1)
 				;
+#else
+#if defined FLAC__CPU_X86_64 /* and other 64-bit arch, too */
+			if(mean <= 0x80000000/512) { /* 512: more or less optimal for both 16- and 24-bit input */
+#else
+			if(mean <= 0x80000000/8) { /* 32-bit arch: use 32-bit math if possible */
 #endif
-			if(rice_parameter >= FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER) {
+				FLAC__uint32 k2, mean2 = (FLAC__uint32) mean;
+				rice_parameter = 0; k2 = partition_samples;
+				while(k2*8 < mean2) { /* requires: mean <= (2^31)/8 */
+					rice_parameter += 4; k2 <<= 4; /* tuned for 16-bit input */
+				}
+				while(k2 < mean2) { /* requires: mean <= 2^31 */
+					rice_parameter++; k2 <<= 1;
+				}
+			}
+			else {
+				rice_parameter = 0; k = partition_samples;
+				if(mean <= FLAC__U64L(0x8000000000000000)/128) /* usually mean is _much_ smaller than this value */
+					while(k*128 < mean) { /* requires: mean <= (2^63)/128 */
+						rice_parameter += 8; k <<= 8; /* tuned for 24-bit input */
+					}
+				while(k < mean) { /* requires: mean <= 2^63 */
+					rice_parameter++; k <<= 1;
+				}
+			}
+#endif
+			if(rice_parameter >= rice_parameter_limit) {
 #ifdef DEBUG_VERBOSE
-				fprintf(stderr, "clipping rice_parameter (%u -> %u) @6\n", rice_parameter, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1);
+				fprintf(stderr, "clipping rice_parameter (%u -> %u) @6\n", rice_parameter, rice_parameter_limit - 1);
 #endif
-				rice_parameter = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1;
+				rice_parameter = rice_parameter_limit - 1;
 			}
 
-#ifndef NO_RICE_SEARCH
+			best_partition_bits = (unsigned)(-1);
+#ifdef ENABLE_RICE_PARAMETER_SEARCH
 			if(rice_parameter_search_dist) {
 				if(rice_parameter < rice_parameter_search_dist)
 					min_rice_parameter = 0;
@@ -2963,61 +4236,43 @@
 				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) {
+				if(max_rice_parameter >= rice_parameter_limit) {
 #ifdef DEBUG_VERBOSE
-					fprintf(stderr, "clipping rice_parameter (%u -> %u) @7\n", max_rice_parameter, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1);
+					fprintf(stderr, "clipping rice_parameter (%u -> %u) @7\n", max_rice_parameter, rice_parameter_limit - 1);
 #endif
-					max_rice_parameter = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1;
+					max_rice_parameter = rice_parameter_limit - 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;
+#ifdef EXACT_RICE_BITS_CALCULATION
+				partition_bits = count_rice_bits_in_partition_(rice_parameter, partition_samples, residual+residual_sample);
 #else
-				const unsigned rice_parameter_estimate = rice_parameter-1;
-				partition_bits = (1+rice_parameter) * partition_samples;
+				partition_bits = count_rice_bits_in_partition_(rice_parameter, partition_samples, abs_residual_partition_sums[partition]);
 #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;
 				}
+#ifdef ENABLE_RICE_PARAMETER_SEARCH
 			}
 #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) {
+				partition_bits = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN + FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN + raw_bits_per_partition[partition] * partition_samples;
+				if(partition_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;
+					best_rice_parameter = 0; /* will be converted to appropriate escape parameter later */
+					best_partition_bits = partition_bits;
 				}
+				else
+					raw_bits[partition] = 0;
 			}
 			parameters[partition] = best_rice_parameter;
 			bits_ += best_partition_bits;
+			residual_sample += partition_samples;
 		}
 	}
 
@@ -3078,10 +4333,10 @@
 	FLAC__ASSERT(fifo->tail <= fifo->size);
 }
 
-FLAC__StreamDecoderReadStatus verify_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data)
+FLAC__StreamDecoderReadStatus verify_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
 {
 	FLAC__StreamEncoder *encoder = (FLAC__StreamEncoder*)client_data;
-	const unsigned encoded_bytes = encoder->private_->verify.output.bytes;
+	const size_t encoded_bytes = encoder->private_->verify.output.bytes;
 	(void)decoder;
 
 	if(encoder->private_->verify.needs_magic_hack) {
@@ -3113,10 +4368,12 @@
 {
 	FLAC__StreamEncoder *encoder = (FLAC__StreamEncoder *)client_data;
 	unsigned channel;
-	const unsigned channels = FLAC__stream_decoder_get_channels(decoder);
+	const unsigned channels = frame->header.channels;
 	const unsigned blocksize = frame->header.blocksize;
 	const unsigned bytes_per_block = sizeof(FLAC__int32) * blocksize;
 
+	(void)decoder;
+
 	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;
@@ -3143,10 +4400,10 @@
 		}
 	}
 	/* 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;
+	FLAC__ASSERT(encoder->private_->verify.input_fifo.tail <= OVERREAD_);
+	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 * sizeof(encoder->private_->verify.input_fifo.data[0][0]));
 	return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
 }
 
@@ -3160,4 +4417,109 @@
 	FLAC__StreamEncoder *encoder = (FLAC__StreamEncoder*)client_data;
 	(void)decoder, (void)status;
 	encoder->protected_->state = FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR;
+}
+
+FLAC__StreamEncoderReadStatus file_read_callback_(const FLAC__StreamEncoder *encoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
+{
+	(void)client_data;
+
+	*bytes = fread(buffer, 1, *bytes, encoder->private_->file);
+	if (*bytes == 0) {
+		if (feof(encoder->private_->file))
+			return FLAC__STREAM_ENCODER_READ_STATUS_END_OF_STREAM;
+		else if (ferror(encoder->private_->file))
+			return FLAC__STREAM_ENCODER_READ_STATUS_ABORT;
+	}
+	return FLAC__STREAM_ENCODER_READ_STATUS_CONTINUE;
+}
+
+FLAC__StreamEncoderSeekStatus file_seek_callback_(const FLAC__StreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data)
+{
+	(void)client_data;
+
+	if(fseeko(encoder->private_->file, (FLAC__off_t)absolute_byte_offset, SEEK_SET) < 0)
+		return FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR;
+	else
+		return FLAC__STREAM_ENCODER_SEEK_STATUS_OK;
+}
+
+FLAC__StreamEncoderTellStatus file_tell_callback_(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
+{
+	FLAC__off_t offset;
+
+	(void)client_data;
+
+	offset = ftello(encoder->private_->file);
+
+	if(offset < 0) {
+		return FLAC__STREAM_ENCODER_TELL_STATUS_ERROR;
+	}
+	else {
+		*absolute_byte_offset = (FLAC__uint64)offset;
+		return FLAC__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 file_write_callback_(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame, void *client_data)
+{
+	(void)client_data, (void)current_frame;
+
+	if(local__fwrite(buffer, sizeof(FLAC__byte), bytes, encoder->private_->file) == bytes) {
+		FLAC__bool call_it = 0 != encoder->private_->progress_callback && (
+#if FLAC__HAS_OGG
+			/* We would like to be able to use 'samples > 0' in the
+			 * clause here but currently because of the nature of our
+			 * Ogg writing implementation, 'samples' is always 0 (see
+			 * ogg_encoder_aspect.c).  The downside is extra progress
+			 * callbacks.
+			 */
+			encoder->private_->is_ogg? true :
+#endif
+			samples > 0
+		);
+		if(call_it) {
+			/* NOTE: We have to add +bytes, +samples, and +1 to the stats
+			 * because at this point in the callback chain, the stats
+			 * have not been updated.  Only after we return and control
+			 * gets back to write_frame_() are the stats updated
+			 */
+			encoder->private_->progress_callback(encoder, encoder->private_->bytes_written+bytes, encoder->private_->samples_written+samples, encoder->private_->frames_written+(samples?1:0), encoder->private_->total_frames_estimate, encoder->private_->client_data);
+		}
+		return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
+	}
+	else
+		return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
+}
+
+/*
+ * This will forcibly set stdout to binary mode (for OSes that require it)
+ */
+FILE *get_binary_stdout_(void)
+{
+	/* 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(stdout), _O_BINARY);
+#elif defined __CYGWIN__
+	/* almost certainly not needed for any modern Cygwin, but let's be safe... */
+	setmode(_fileno(stdout), _O_BINARY);
+#elif defined __EMX__
+	setmode(fileno(stdout), O_BINARY);
+#endif
+
+	return stdout;
 }
--- a/sys/src/cmd/audio/libFLAC/stream_encoder_framing.c
+++ b/sys/src/cmd/audio/libFLAC/stream_encoder_framing.c
@@ -1,5 +1,6 @@
 /* libFLAC - Free Lossless Audio Codec library
- * Copyright (C) 2000,2001,2002,2003,2004  Josh Coalson
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2014  Xiph.Org Foundation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -29,6 +30,10 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
 #include <stdio.h>
 #include <string.h> /* for strlen() */
 #include "private/stream_encoder_framing.h"
@@ -35,23 +40,18 @@
 #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__BitWriter *bw, const FLAC__EntropyCodingMethod *method);
+static FLAC__bool add_residual_partitioned_rice_(FLAC__BitWriter *bw, const FLAC__int32 residual[], const unsigned residual_samples, const unsigned predictor_order, const unsigned rice_parameters[], const unsigned raw_bits[], const unsigned partition_order, const FLAC__bool is_extended);
 
-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)
+FLAC__bool FLAC__add_metadata_block(const FLAC__StreamMetadata *metadata, FLAC__BitWriter *bw)
 {
 	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))
+	if(!FLAC__bitwriter_write_raw_uint32(bw, 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))
+	if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->type, FLAC__STREAM_METADATA_TYPE_LEN))
 		return false;
 
 	/*
@@ -64,137 +64,170 @@
 		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))
+	if(!FLAC__bitwriter_write_raw_uint32(bw, 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))
+			if(!FLAC__bitwriter_write_raw_uint32(bw, 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))
+			if(!FLAC__bitwriter_write_raw_uint32(bw, 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))
+			if(!FLAC__bitwriter_write_raw_uint32(bw, 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))
+			if(!FLAC__bitwriter_write_raw_uint32(bw, 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))
+			if(!FLAC__bitwriter_write_raw_uint32(bw, 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))
+			if(!FLAC__bitwriter_write_raw_uint32(bw, 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))
+			if(!FLAC__bitwriter_write_raw_uint32(bw, 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))
+			if(!FLAC__bitwriter_write_raw_uint64(bw, 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))
+			if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.stream_info.md5sum, 16))
 				return false;
 			break;
 		case FLAC__METADATA_TYPE_PADDING:
-			if(!FLAC__bitbuffer_write_zeroes(bb, metadata->length * 8))
+			if(!FLAC__bitwriter_write_zeroes(bw, 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))
+			if(!FLAC__bitwriter_write_byte_block(bw, 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)))
+			if(!FLAC__bitwriter_write_byte_block(bw, 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))
+				if(!FLAC__bitwriter_write_raw_uint64(bw, 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))
+				if(!FLAC__bitwriter_write_raw_uint64(bw, 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))
+				if(!FLAC__bitwriter_write_raw_uint32(bw, 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))
+			if(!FLAC__bitwriter_write_raw_uint32_little_endian(bw, vendor_string_length))
 				return false;
-			if(!FLAC__bitbuffer_write_byte_block(bb, (const FLAC__byte*)FLAC__VENDOR_STRING, vendor_string_length))
+			if(!FLAC__bitwriter_write_byte_block(bw, (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))
+			if(!FLAC__bitwriter_write_raw_uint32_little_endian(bw, 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))
+				if(!FLAC__bitwriter_write_raw_uint32_little_endian(bw, 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))
+				if(!FLAC__bitwriter_write_byte_block(bw, 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))
+			if(!FLAC__bitwriter_write_byte_block(bw, (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))
+			if(!FLAC__bitwriter_write_raw_uint64(bw, 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))
+			if(!FLAC__bitwriter_write_raw_uint32(bw, 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))
+			if(!FLAC__bitwriter_write_zeroes(bw, 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))
+			if(!FLAC__bitwriter_write_raw_uint32(bw, 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))
+				if(!FLAC__bitwriter_write_raw_uint64(bw, 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))
+				if(!FLAC__bitwriter_write_raw_uint32(bw, 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))
+				if(!FLAC__bitwriter_write_byte_block(bw, (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))
+				if(!FLAC__bitwriter_write_raw_uint32(bw, 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))
+				if(!FLAC__bitwriter_write_raw_uint32(bw, 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))
+				if(!FLAC__bitwriter_write_zeroes(bw, 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))
+				if(!FLAC__bitwriter_write_raw_uint32(bw, 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;
+					const FLAC__StreamMetadata_CueSheet_Index *indx = track->indices + j;
 
-					if(!FLAC__bitbuffer_write_raw_uint64(bb, index->offset, FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN))
+					if(!FLAC__bitwriter_write_raw_uint64(bw, indx->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))
+					if(!FLAC__bitwriter_write_raw_uint32(bw, indx->number, FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN))
 						return false;
-					if(!FLAC__bitbuffer_write_zeroes(bb, FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN))
+					if(!FLAC__bitwriter_write_zeroes(bw, FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN))
 						return false;
 				}
 			}
 			break;
+		case FLAC__METADATA_TYPE_PICTURE:
+			{
+				size_t len;
+				if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.picture.type, FLAC__STREAM_METADATA_PICTURE_TYPE_LEN))
+					return false;
+				len = strlen(metadata->data.picture.mime_type);
+				if(!FLAC__bitwriter_write_raw_uint32(bw, len, FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN))
+					return false;
+				if(!FLAC__bitwriter_write_byte_block(bw, (const FLAC__byte*)metadata->data.picture.mime_type, len))
+					return false;
+				len = strlen((const char *)metadata->data.picture.description);
+				if(!FLAC__bitwriter_write_raw_uint32(bw, len, FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN))
+					return false;
+				if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.picture.description, len))
+					return false;
+				if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.picture.width, FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN))
+					return false;
+				if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.picture.height, FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN))
+					return false;
+				if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.picture.depth, FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN))
+					return false;
+				if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.picture.colors, FLAC__STREAM_METADATA_PICTURE_COLORS_LEN))
+					return false;
+				if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.picture.data_length, FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN))
+					return false;
+				if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.picture.data, metadata->data.picture.data_length))
+					return false;
+			}
+			break;
 		default:
-			if(!FLAC__bitbuffer_write_byte_block(bb, metadata->data.unknown.data, metadata->length))
+			if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.unknown.data, metadata->length))
 				return false;
 			break;
 	}
 
-	FLAC__ASSERT(FLAC__bitbuffer_is_byte_aligned(bb));
+	FLAC__ASSERT(FLAC__bitwriter_is_byte_aligned(bw));
 	return true;
 }
 
-FLAC__bool FLAC__frame_add_header(const FLAC__FrameHeader *header, FLAC__bool streamable_subset, FLAC__BitBuffer *bb)
+FLAC__bool FLAC__frame_add_header(const FLAC__FrameHeader *header, FLAC__BitWriter *bw)
 {
 	unsigned u, blocksize_hint, sample_rate_hint;
+	FLAC__byte crc;
 
-	FLAC__ASSERT(FLAC__bitbuffer_is_byte_aligned(bb));
+	FLAC__ASSERT(FLAC__bitwriter_is_byte_aligned(bw));
 
-	if(!FLAC__bitbuffer_write_raw_uint32(bb, FLAC__FRAME_HEADER_SYNC, FLAC__FRAME_HEADER_SYNC_LEN))
+	if(!FLAC__bitwriter_write_raw_uint32(bw, FLAC__FRAME_HEADER_SYNC, FLAC__FRAME_HEADER_SYNC_LEN))
 		return false;
 
-	if(!FLAC__bitbuffer_write_raw_uint32(bb, 0, FLAC__FRAME_HEADER_RESERVED_LEN))
+	if(!FLAC__bitwriter_write_raw_uint32(bw, 0, FLAC__FRAME_HEADER_RESERVED_LEN))
 		return false;
 
+	if(!FLAC__bitwriter_write_raw_uint32(bw, (header->number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER)? 0 : 1, FLAC__FRAME_HEADER_BLOCKING_STRATEGY_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);
@@ -216,28 +249,27 @@
 		default:
 			if(header->blocksize <= 0x100)
 				blocksize_hint = u = 6;
-			else if(header->blocksize <= 0x10000)
+			else
 				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))
+	if(!FLAC__bitwriter_write_raw_uint32(bw, 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;
+		case  88200: u = 1; break;
+		case 176400: u = 2; break;
+		case 192000: u = 3; break;
+		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;
@@ -245,15 +277,11 @@
 				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))
+	if(!FLAC__bitwriter_write_raw_uint32(bw, 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);
@@ -276,7 +304,7 @@
 		default:
 			FLAC__ASSERT(0);
 	}
-	if(!FLAC__bitbuffer_write_raw_uint32(bb, u, FLAC__FRAME_HEADER_CHANNEL_ASSIGNMENT_LEN))
+	if(!FLAC__bitwriter_write_raw_uint32(bw, 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));
@@ -288,74 +316,91 @@
 		case 24: u = 6; break;
 		default: u = 0; break;
 	}
-	if(!FLAC__bitbuffer_write_raw_uint32(bb, u, FLAC__FRAME_HEADER_BITS_PER_SAMPLE_LEN))
+	if(!FLAC__bitwriter_write_raw_uint32(bw, u, FLAC__FRAME_HEADER_BITS_PER_SAMPLE_LEN))
 		return false;
 
-	if(!FLAC__bitbuffer_write_raw_uint32(bb, 0, FLAC__FRAME_HEADER_ZERO_PAD_LEN))
+	if(!FLAC__bitwriter_write_raw_uint32(bw, 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(header->number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER) {
+		if(!FLAC__bitwriter_write_utf8_uint32(bw, header->number.frame_number))
+			return false;
+	}
+	else {
+		if(!FLAC__bitwriter_write_utf8_uint64(bw, header->number.sample_number))
+			return false;
+	}
 
 	if(blocksize_hint)
-		if(!FLAC__bitbuffer_write_raw_uint32(bb, header->blocksize-1, (blocksize_hint==6)? 8:16))
+		if(!FLAC__bitwriter_write_raw_uint32(bw, 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))
+			if(!FLAC__bitwriter_write_raw_uint32(bw, header->sample_rate / 1000, 8))
 				return false;
 			break;
 		case 13:
-			if(!FLAC__bitbuffer_write_raw_uint32(bb, header->sample_rate, 16))
+			if(!FLAC__bitwriter_write_raw_uint32(bw, header->sample_rate, 16))
 				return false;
 			break;
 		case 14:
-			if(!FLAC__bitbuffer_write_raw_uint32(bb, header->sample_rate / 10, 16))
+			if(!FLAC__bitwriter_write_raw_uint32(bw, 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))
+	if(!FLAC__bitwriter_get_write_crc8(bw, &crc))
 		return false;
+	if(!FLAC__bitwriter_write_raw_uint32(bw, crc, 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 FLAC__subframe_add_constant(const FLAC__Subframe_Constant *subframe, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitWriter *bw)
 {
 	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)
+		FLAC__bitwriter_write_raw_uint32(bw, 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__bitwriter_write_unary_unsigned(bw, wasted_bits-1) : true) &&
+		FLAC__bitwriter_write_raw_int32(bw, 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)
+FLAC__bool FLAC__subframe_add_fixed(const FLAC__Subframe_Fixed *subframe, unsigned residual_samples, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitWriter *bw)
 {
 	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))
+	if(!FLAC__bitwriter_write_raw_uint32(bw, 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))
+		if(!FLAC__bitwriter_write_unary_unsigned(bw, wasted_bits-1))
 			return false;
 
 	for(i = 0; i < subframe->order; i++)
-		if(!FLAC__bitbuffer_write_raw_int32(bb, subframe->warmup[i], subframe_bps))
+		if(!FLAC__bitwriter_write_raw_int32(bw, subframe->warmup[i], subframe_bps))
 			return false;
 
-	if(!add_entropy_coding_method_(bb, &subframe->entropy_coding_method))
+	if(!add_entropy_coding_method_(bw, &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))
+		case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2:
+			if(!add_residual_partitioned_rice_(
+				bw,
+				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,
+				/*is_extended=*/subframe->entropy_coding_method.type == FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2
+			))
 				return false;
 			break;
 		default:
@@ -365,33 +410,43 @@
 	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)
+FLAC__bool FLAC__subframe_add_lpc(const FLAC__Subframe_LPC *subframe, unsigned residual_samples, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitWriter *bw)
 {
 	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))
+	if(!FLAC__bitwriter_write_raw_uint32(bw, 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))
+		if(!FLAC__bitwriter_write_unary_unsigned(bw, wasted_bits-1))
 			return false;
 
 	for(i = 0; i < subframe->order; i++)
-		if(!FLAC__bitbuffer_write_raw_int32(bb, subframe->warmup[i], subframe_bps))
+		if(!FLAC__bitwriter_write_raw_int32(bw, 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))
+	if(!FLAC__bitwriter_write_raw_uint32(bw, 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))
+	if(!FLAC__bitwriter_write_raw_int32(bw, 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))
+		if(!FLAC__bitwriter_write_raw_int32(bw, subframe->qlp_coeff[i], subframe->qlp_coeff_precision))
 			return false;
 
-	if(!add_entropy_coding_method_(bb, &subframe->entropy_coding_method))
+	if(!add_entropy_coding_method_(bw, &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))
+		case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2:
+			if(!add_residual_partitioned_rice_(
+				bw,
+				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,
+				/*is_extended=*/subframe->entropy_coding_method.type == FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2
+			))
 				return false;
 			break;
 		default:
@@ -401,31 +456,32 @@
 	return true;
 }
 
-FLAC__bool FLAC__subframe_add_verbatim(const FLAC__Subframe_Verbatim *subframe, unsigned 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__BitWriter *bw)
 {
 	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))
+	if(!FLAC__bitwriter_write_raw_uint32(bw, 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))
+		if(!FLAC__bitwriter_write_unary_unsigned(bw, wasted_bits-1))
 			return false;
 
 	for(i = 0; i < samples; i++)
-		if(!FLAC__bitbuffer_write_raw_int32(bb, signal[i], subframe_bps))
+		if(!FLAC__bitwriter_write_raw_int32(bw, signal[i], subframe_bps))
 			return false;
 
 	return true;
 }
 
-FLAC__bool add_entropy_coding_method_(FLAC__BitBuffer *bb, const FLAC__EntropyCodingMethod *method)
+FLAC__bool add_entropy_coding_method_(FLAC__BitWriter *bw, const FLAC__EntropyCodingMethod *method)
 {
-	if(!FLAC__bitbuffer_write_raw_uint32(bb, method->type, FLAC__ENTROPY_CODING_METHOD_TYPE_LEN))
+	if(!FLAC__bitwriter_write_raw_uint32(bw, 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))
+		case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2:
+			if(!FLAC__bitwriter_write_raw_uint32(bw, method->data.partitioned_rice.order, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN))
 				return false;
 			break;
 		default:
@@ -434,29 +490,28 @@
 	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)
+FLAC__bool add_residual_partitioned_rice_(FLAC__BitWriter *bw, const FLAC__int32 residual[], const unsigned residual_samples, const unsigned predictor_order, const unsigned rice_parameters[], const unsigned raw_bits[], const unsigned partition_order, const FLAC__bool is_extended)
 {
+	const unsigned plen = is_extended? FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN : FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN;
+	const unsigned pesc = is_extended? FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER : FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER;
+
 	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
-			}
+		if(raw_bits[0] == 0) {
+			if(!FLAC__bitwriter_write_raw_uint32(bw, rice_parameters[0], plen))
+				return false;
+			if(!FLAC__bitwriter_write_rice_signed_block(bw, residual, residual_samples, rice_parameters[0]))
+				return false;
 		}
 		else {
-			if(!FLAC__bitbuffer_write_raw_uint32(bb, raw_bits[0], FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN))
+			FLAC__ASSERT(rice_parameters[0] == 0);
+			if(!FLAC__bitwriter_write_raw_uint32(bw, pesc, plen))
 				return false;
+			if(!FLAC__bitwriter_write_raw_uint32(bw, 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]))
+				if(!FLAC__bitwriter_write_raw_int32(bw, residual[i], raw_bits[0]))
 					return false;
 			}
 		}
@@ -467,28 +522,23 @@
 		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
-				}
+			if(raw_bits[i] == 0) {
+				if(!FLAC__bitwriter_write_raw_uint32(bw, rice_parameters[i], plen))
+					return false;
+				if(!FLAC__bitwriter_write_rice_signed_block(bw, residual+k_last, k-k_last, rice_parameters[i]))
+					return false;
 			}
 			else {
-				if(!FLAC__bitbuffer_write_raw_uint32(bb, raw_bits[i], FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN))
+				if(!FLAC__bitwriter_write_raw_uint32(bw, pesc, plen))
 					return false;
+				if(!FLAC__bitwriter_write_raw_uint32(bw, 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]))
+					if(!FLAC__bitwriter_write_raw_int32(bw, residual[j], raw_bits[i]))
 						return false;
 				}
 			}
--- /dev/null
+++ b/sys/src/cmd/audio/libFLAC/window.c
@@ -1,0 +1,282 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2006-2009  Josh Coalson
+ * Copyright (C) 2011-2014  Xiph.Org Foundation
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <math.h>
+#include "share/compat.h"
+#include "FLAC/assert.h"
+#include "FLAC/format.h"
+#include "private/window.h"
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+
+
+void FLAC__window_bartlett(FLAC__real *window, const FLAC__int32 L)
+{
+	const FLAC__int32 N = L - 1;
+	FLAC__int32 n;
+
+	if (L & 1) {
+		for (n = 0; n <= N/2; n++)
+			window[n] = 2.0f * n / (float)N;
+		for (; n <= N; n++)
+			window[n] = 2.0f - 2.0f * n / (float)N;
+	}
+	else {
+		for (n = 0; n <= L/2-1; n++)
+			window[n] = 2.0f * n / (float)N;
+		for (; n <= N; n++)
+			window[n] = 2.0f - 2.0f * n / (float)N;
+	}
+}
+
+void FLAC__window_bartlett_hann(FLAC__real *window, const FLAC__int32 L)
+{
+	const FLAC__int32 N = L - 1;
+	FLAC__int32 n;
+
+	for (n = 0; n < L; n++)
+		window[n] = (FLAC__real)(0.62f - 0.48f * fabs((float)n/(float)N-0.5f) - 0.38f * cos(2.0f * M_PI * ((float)n/(float)N)));
+}
+
+void FLAC__window_blackman(FLAC__real *window, const FLAC__int32 L)
+{
+	const FLAC__int32 N = L - 1;
+	FLAC__int32 n;
+
+	for (n = 0; n < L; n++)
+		window[n] = (FLAC__real)(0.42f - 0.5f * cos(2.0f * M_PI * n / N) + 0.08f * cos(4.0f * M_PI * n / N));
+}
+
+/* 4-term -92dB side-lobe */
+void FLAC__window_blackman_harris_4term_92db_sidelobe(FLAC__real *window, const FLAC__int32 L)
+{
+	const FLAC__int32 N = L - 1;
+	FLAC__int32 n;
+
+	for (n = 0; n <= N; n++)
+		window[n] = (FLAC__real)(0.35875f - 0.48829f * cos(2.0f * M_PI * n / N) + 0.14128f * cos(4.0f * M_PI * n / N) - 0.01168f * cos(6.0f * M_PI * n / N));
+}
+
+void FLAC__window_connes(FLAC__real *window, const FLAC__int32 L)
+{
+	const FLAC__int32 N = L - 1;
+	const double N2 = (double)N / 2.;
+	FLAC__int32 n;
+
+	for (n = 0; n <= N; n++) {
+		double k = ((double)n - N2) / N2;
+		k = 1.0f - k * k;
+		window[n] = (FLAC__real)(k * k);
+	}
+}
+
+void FLAC__window_flattop(FLAC__real *window, const FLAC__int32 L)
+{
+	const FLAC__int32 N = L - 1;
+	FLAC__int32 n;
+
+	for (n = 0; n < L; n++)
+		window[n] = (FLAC__real)(1.0f - 1.93f * cos(2.0f * M_PI * n / N) + 1.29f * cos(4.0f * M_PI * n / N) - 0.388f * cos(6.0f * M_PI * n / N) + 0.0322f * cos(8.0f * M_PI * n / N));
+}
+
+void FLAC__window_gauss(FLAC__real *window, const FLAC__int32 L, const FLAC__real stddev)
+{
+	const FLAC__int32 N = L - 1;
+	const double N2 = (double)N / 2.;
+	FLAC__int32 n;
+
+	for (n = 0; n <= N; n++) {
+		const double k = ((double)n - N2) / (stddev * N2);
+		window[n] = (FLAC__real)exp(-0.5f * k * k);
+	}
+}
+
+void FLAC__window_hamming(FLAC__real *window, const FLAC__int32 L)
+{
+	const FLAC__int32 N = L - 1;
+	FLAC__int32 n;
+
+	for (n = 0; n < L; n++)
+		window[n] = (FLAC__real)(0.54f - 0.46f * cos(2.0f * M_PI * n / N));
+}
+
+void FLAC__window_hann(FLAC__real *window, const FLAC__int32 L)
+{
+	const FLAC__int32 N = L - 1;
+	FLAC__int32 n;
+
+	for (n = 0; n < L; n++)
+		window[n] = (FLAC__real)(0.5f - 0.5f * cos(2.0f * M_PI * n / N));
+}
+
+void FLAC__window_kaiser_bessel(FLAC__real *window, const FLAC__int32 L)
+{
+	const FLAC__int32 N = L - 1;
+	FLAC__int32 n;
+
+	for (n = 0; n < L; n++)
+		window[n] = (FLAC__real)(0.402f - 0.498f * cos(2.0f * M_PI * n / N) + 0.098f * cos(4.0f * M_PI * n / N) - 0.001f * cos(6.0f * M_PI * n / N));
+}
+
+void FLAC__window_nuttall(FLAC__real *window, const FLAC__int32 L)
+{
+	const FLAC__int32 N = L - 1;
+	FLAC__int32 n;
+
+	for (n = 0; n < L; n++)
+		window[n] = (FLAC__real)(0.3635819f - 0.4891775f*cos(2.0f*M_PI*n/N) + 0.1365995f*cos(4.0f*M_PI*n/N) - 0.0106411f*cos(6.0f*M_PI*n/N));
+}
+
+void FLAC__window_rectangle(FLAC__real *window, const FLAC__int32 L)
+{
+	FLAC__int32 n;
+
+	for (n = 0; n < L; n++)
+		window[n] = 1.0f;
+}
+
+void FLAC__window_triangle(FLAC__real *window, const FLAC__int32 L)
+{
+	FLAC__int32 n;
+
+	if (L & 1) {
+		for (n = 1; n <= (L+1)/2; n++)
+			window[n-1] = 2.0f * n / ((float)L + 1.0f);
+		for (; n <= L; n++)
+			window[n-1] = (float)(2 * (L - n + 1)) / ((float)L + 1.0f);
+	}
+	else {
+		for (n = 1; n <= L/2; n++)
+			window[n-1] = 2.0f * n / ((float)L + 1.0f);
+		for (; n <= L; n++)
+			window[n-1] = (float)(2 * (L - n + 1)) / ((float)L + 1.0f);
+	}
+}
+
+void FLAC__window_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p)
+{
+	if (p <= 0.0)
+		FLAC__window_rectangle(window, L);
+	else if (p >= 1.0)
+		FLAC__window_hann(window, L);
+	else {
+		const FLAC__int32 Np = (FLAC__int32)(p / 2.0f * L) - 1;
+		FLAC__int32 n;
+		/* start with rectangle... */
+		FLAC__window_rectangle(window, L);
+		/* ...replace ends with hann */
+		if (Np > 0) {
+			for (n = 0; n <= Np; n++) {
+				window[n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * n / Np));
+				window[L-Np-1+n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * (n+Np) / Np));
+			}
+		}
+	}
+}
+
+void FLAC__window_partial_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p, const FLAC__real start, const FLAC__real end)
+{
+	const FLAC__int32 start_n = (FLAC__int32)(start * L);
+	const FLAC__int32 end_n = (FLAC__int32)(end * L);
+	const FLAC__int32 N = end_n - start_n;
+	FLAC__int32 Np, n, i;
+
+	if (p <= 0.0f)
+		FLAC__window_partial_tukey(window, L, 0.05f, start, end);
+	else if (p >= 1.0f)
+		FLAC__window_partial_tukey(window, L, 0.95f, start, end);
+	else {
+
+		Np = (FLAC__int32)(p / 2.0f * N);
+
+		for (n = 0; n < start_n && n < L; n++)
+			window[n] = 0.0f;
+		for (i = 1; n < (start_n+Np) && n < L; n++, i++)
+			window[n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * i / Np));
+		for (; n < (end_n-Np) && n < L; n++)
+			window[n] = 1.0f;
+		for (i = Np; n < end_n && n < L; n++, i--)
+			window[n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * i / Np));
+		for (; n < L; n++)
+			window[n] = 0.0f;
+	}
+}
+
+void FLAC__window_punchout_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p, const FLAC__real start, const FLAC__real end)
+{
+	const FLAC__int32 start_n = (FLAC__int32)(start * L);
+	const FLAC__int32 end_n = (FLAC__int32)(end * L);
+	FLAC__int32 Ns, Ne, n, i;
+
+	if (p <= 0.0f)
+		FLAC__window_punchout_tukey(window, L, 0.05f, start, end);
+	else if (p >= 1.0f)
+		FLAC__window_punchout_tukey(window, L, 0.95f, start, end);
+	else {
+
+		Ns = (FLAC__int32)(p / 2.0f * start_n);
+		Ne = (FLAC__int32)(p / 2.0f * (L - end_n));
+
+		for (n = 0, i = 1; n < Ns && n < L; n++, i++)
+			window[n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * i / Ns));
+		for (; n < start_n-Ns && n < L; n++)
+			window[n] = 1.0f;
+		for (i = Ns; n < start_n && n < L; n++, i--)
+			window[n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * i / Ns));
+		for (; n < end_n && n < L; n++)
+			window[n] = 0.0f;
+		for (i = 1; n < end_n+Ne && n < L; n++, i++)
+			window[n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * i / Ne));
+		for (; n < L - (Ne) && n < L; n++)
+			window[n] = 1.0f;
+		for (i = Ne; n < L; n++, i--)
+			window[n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * i / Ne));
+	}
+}
+
+void FLAC__window_welch(FLAC__real *window, const FLAC__int32 L)
+{
+	const FLAC__int32 N = L - 1;
+	const double N2 = (double)N / 2.;
+	FLAC__int32 n;
+
+	for (n = 0; n <= N; n++) {
+		const double k = ((double)n - N2) / N2;
+		window[n] = (FLAC__real)(1.0f - k * k);
+	}
+}
+
+#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */